diff options
1648 files changed, 35121 insertions, 14911 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index e5c059ecbfb7..8b95679f318f 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -230,6 +230,17 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +java_aconfig_library { + name: "telephony_flags_core_java_exported_lib", + aconfig_declarations: "telephony_flags", + mode: "exported", + min_sdk_version: "30", + apex_available: [ + "com.android.wifi", + ], + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + cc_aconfig_library { name: "telephony_flags_c_lib", aconfig_declarations: "telephony_flags", diff --git a/apct-tests/perftests/core/src/android/os/TracePerfTest.java b/apct-tests/perftests/core/src/android/os/TracePerfTest.java index bf7c96a3cb85..0b941c9d83c0 100644 --- a/apct-tests/perftests/core/src/android/os/TracePerfTest.java +++ b/apct-tests/perftests/core/src/android/os/TracePerfTest.java @@ -139,6 +139,30 @@ public class TracePerfTest { } } + @Test + public void testInstantPerfettoWithProto() { + PerfettoTrace.begin(FOO_CATEGORY, "message_queue_receive") + .beginProto() + .beginNested(2004 /* message_queue */) + .addField(1 /* sending_thread_name */, "foo") + .endNested() + .endProto() + .addTerminatingFlow(5) + .emit(); + + BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + PerfettoTrace.begin(FOO_CATEGORY, "message_queue_receive") + .beginProto() + .beginNested(2004 /* message_queue */) + .addField(1 /* sending_thread_name */, "foo") + .endNested() + .endProto() + .addTerminatingFlow(5) + .emit(); + } + } + private static TraceConfig getTraceConfig(String cat) { BufferConfig bufferConfig = BufferConfig.newBuilder().setSizeKb(1024).build(); TrackEventConfig trackEventConfig = TrackEventConfig 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 ebfda527001d..010006edc995 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java @@ -809,7 +809,11 @@ public final class JobServiceContext implements ServiceConnection { if (!verifyCallerLocked(cb)) { return; } - + if (mVerb != VERB_EXECUTING) { + // Any state other than executing means the + // job is in transient or stopped state + return; + } executing = getRunningJobLocked(); } if (executing != null && jobId == executing.getJobId()) { diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index 1f15daf1ba47..335dc97bf964 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -178,8 +178,8 @@ class IdmapHeader { }; struct IdmapConstraint { - // Constraint type can be TYPE_DISPLAY_ID or TYP_DEVICE_ID, please refer - // to ConstraintType in OverlayConstraint.java + // Constraint type can be android::kOverlayConstraintTypeDisplayId or + // android::kOverlayConstraintTypeDeviceId uint32_t constraint_type; uint32_t constraint_value; diff --git a/core/api/current.txt b/core/api/current.txt index 60be8a76e3b2..9ebb5068bf19 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -17621,6 +17621,7 @@ package android.graphics { method public void setIntUniform(@NonNull String, int, int, int); method public void setIntUniform(@NonNull String, int, int, int, int); method public void setIntUniform(@NonNull String, @NonNull int[]); + method @FlaggedApi("com.android.graphics.hwui.flags.shader_color_space") public void setWorkingColorSpace(@Nullable android.graphics.ColorSpace); } @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public class RuntimeXfermode extends android.graphics.Xfermode { @@ -18111,6 +18112,7 @@ package android.graphics.drawable { method public void setThickness(@Px int); method public void setThicknessRatio(@FloatRange(from=0.0f, fromInclusive=false) float); method public void setUseLevel(boolean); + field @FlaggedApi("com.android.graphics.flags.gradient_drawable_shape_rounded_cap") public static final int ARC = 4; // 0x4 field public static final int LINE = 2; // 0x2 field public static final int LINEAR_GRADIENT = 0; // 0x0 field public static final int OVAL = 1; // 0x1 @@ -38341,7 +38343,7 @@ package android.provider { field @FlaggedApi("com.android.media.flags.enable_privileged_routing_for_media_routing_control") public static final String ACTION_REQUEST_MEDIA_ROUTING_CONTROL = "android.settings.REQUEST_MEDIA_ROUTING_CONTROL"; field public static final String ACTION_REQUEST_SCHEDULE_EXACT_ALARM = "android.settings.REQUEST_SCHEDULE_EXACT_ALARM"; field public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String ACTION_SATELLITE_SETTING = "android.settings.SATELLITE_SETTING"; + field public static final String ACTION_SATELLITE_SETTING = "android.settings.SATELLITE_SETTING"; field public static final String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"; field public static final String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"; field public static final String ACTION_SETTINGS = "android.settings.SETTINGS"; @@ -44989,7 +44991,7 @@ package android.telephony { field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_CARRIER_SUPPORTED_SATELLITE_NOTIFICATION_HYSTERESIS_SEC_INT = "carrier_supported_satellite_notification_hysteresis_sec_int"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE = "carrier_supported_satellite_services_per_provider_bundle"; + field public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE = "carrier_supported_satellite_services_per_provider_bundle"; field public static final String KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL = "carrier_supports_opp_data_auto_provisioning_bool"; field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool"; field public static final String KEY_CARRIER_SUPPORTS_TETHERING_BOOL = "carrier_supports_tethering_bool"; @@ -45122,9 +45124,9 @@ package android.telephony { field public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl"; field public static final String KEY_MMS_USER_AGENT_STRING = "userAgent"; field public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY = "ntn_lte_rsrp_thresholds_int_array"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "ntn_lte_rsrq_thresholds_int_array"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "ntn_lte_rssnr_thresholds_int_array"; + field public static final String KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY = "ntn_lte_rsrp_thresholds_int_array"; + field public static final String KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "ntn_lte_rsrq_thresholds_int_array"; + field public static final String KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "ntn_lte_rssnr_thresholds_int_array"; field public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network"; field public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array"; field public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool"; @@ -45140,7 +45142,7 @@ package android.telephony { field public static final String KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG = "opportunistic_network_max_backoff_time_long"; field public static final String KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG = "opportunistic_network_ping_pong_time_long"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL = "override_wfc_roaming_mode_while_using_ntn_bool"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT = "parameters_used_for_ntn_lte_signal_bar_int"; + field public static final String KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT = "parameters_used_for_ntn_lte_signal_bar_int"; field public static final String KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL = "ping_test_before_data_switch_bool"; field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool"; field @FlaggedApi("com.android.internal.telephony.flags.hide_prefer_3g_item") public static final String KEY_PREFER_3G_VISIBILITY_BOOL = "prefer_3g_visibility_bool"; @@ -45169,14 +45171,14 @@ package android.telephony { field public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = "rtt_supported_while_roaming_bool"; field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool"; field public static final String KEY_RTT_UPGRADE_SUPPORTED_FOR_DOWNGRADED_VT_CALL_BOOL = "rtt_upgrade_supported_for_downgraded_vt_call"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL = "satellite_attach_supported_bool"; + field public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL = "satellite_attach_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") public static final String KEY_SATELLITE_CONNECTED_NOTIFICATION_THROTTLE_MILLIS_INT = "satellite_connected_notification_throttle_millis_int"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = "satellite_connection_hysteresis_sec_int"; + field public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = "satellite_connection_hysteresis_sec_int"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_DATA_SUPPORT_MODE_INT = "satellite_data_support_mode_int"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_DISPLAY_NAME_STRING = "satellite_display_name_string"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_ENTITLEMENT_APP_NAME_STRING = "satellite_entitlement_app_name_string"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT = "satellite_entitlement_status_refresh_days_int"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL = "satellite_entitlement_supported_bool"; + field public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT = "satellite_entitlement_status_refresh_days_int"; + field public static final String KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL = "satellite_entitlement_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.carrier_roaming_nb_iot_ntn") public static final String KEY_SATELLITE_ESOS_SUPPORTED_BOOL = "satellite_esos_supported_bool"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") public static final String KEY_SATELLITE_IGNORE_DATA_ROAMING_SETTING_BOOL = "satellite_ignore_data_roaming_setting_bool"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING = "satellite_information_redirect_url_string"; @@ -46483,7 +46485,7 @@ package android.telephony { method public boolean isNetworkRegistered(); method public boolean isNetworkRoaming(); method public boolean isNetworkSearching(); - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public boolean isNonTerrestrialNetwork(); + method public boolean isNonTerrestrialNetwork(); method @Deprecated public boolean isRegistered(); method @Deprecated public boolean isRoaming(); method @Deprecated public boolean isSearching(); @@ -46499,7 +46501,7 @@ package android.telephony { field public static final int NR_STATE_RESTRICTED = 1; // 0x1 field public static final int SERVICE_TYPE_DATA = 2; // 0x2 field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SERVICE_TYPE_MMS = 6; // 0x6 + field public static final int SERVICE_TYPE_MMS = 6; // 0x6 field public static final int SERVICE_TYPE_SMS = 3; // 0x3 field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0 field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 @@ -46720,7 +46722,7 @@ package android.telephony { method public boolean getRoaming(); method public int getState(); method public boolean isSearching(); - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public boolean isUsingNonTerrestrialNetwork(); + method public boolean isUsingNonTerrestrialNetwork(); method public void setIsManualSelection(boolean); method public void setOperatorName(String, String, String); method public void setRoaming(boolean); @@ -47859,7 +47861,7 @@ package android.telephony.data { field public static final int TYPE_MMS = 2; // 0x2 field @FlaggedApi("com.android.internal.telephony.flags.oem_paid_private") public static final int TYPE_OEM_PAID = 65536; // 0x10000 field @FlaggedApi("com.android.internal.telephony.flags.oem_paid_private") public static final int TYPE_OEM_PRIVATE = 131072; // 0x20000 - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int TYPE_RCS = 32768; // 0x8000 + field public static final int TYPE_RCS = 32768; // 0x8000 field public static final int TYPE_SUPL = 4; // 0x4 field public static final int TYPE_VSIM = 4096; // 0x1000 field public static final int TYPE_XCAP = 2048; // 0x800 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 0d5ec199b953..137c96714ae4 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4199,7 +4199,7 @@ package android.content.pm { method public void setInstallAsInstantApp(boolean); method public void setInstallAsVirtualPreload(); method public void setRequestDowngrade(boolean); - method @FlaggedApi("android.content.pm.recoverability_detection") @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void setRollbackImpactLevel(int); + method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void setRollbackImpactLevel(int); method @FlaggedApi("android.content.pm.rollback_lifetime") @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void setRollbackLifetimeMillis(long); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged(); } @@ -4374,9 +4374,9 @@ package android.content.pm { field public static final int ROLLBACK_DATA_POLICY_RESTORE = 0; // 0x0 field public static final int ROLLBACK_DATA_POLICY_RETAIN = 2; // 0x2 field public static final int ROLLBACK_DATA_POLICY_WIPE = 1; // 0x1 - field @FlaggedApi("android.content.pm.recoverability_detection") public static final int ROLLBACK_USER_IMPACT_HIGH = 1; // 0x1 - field @FlaggedApi("android.content.pm.recoverability_detection") public static final int ROLLBACK_USER_IMPACT_LOW = 0; // 0x0 - field @FlaggedApi("android.content.pm.recoverability_detection") public static final int ROLLBACK_USER_IMPACT_ONLY_MANUAL = 2; // 0x2 + field public static final int ROLLBACK_USER_IMPACT_HIGH = 1; // 0x1 + field public static final int ROLLBACK_USER_IMPACT_LOW = 0; // 0x0 + field public static final int ROLLBACK_USER_IMPACT_ONLY_MANUAL = 2; // 0x2 field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_HIDDEN = 0; // 0x0 field public static final int SYSTEM_APP_STATE_HIDDEN_UNTIL_INSTALLED_VISIBLE = 1; // 0x1 field public static final int SYSTEM_APP_STATE_INSTALLED = 2; // 0x2 @@ -15285,7 +15285,7 @@ package android.telephony { method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean); - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull public android.telephony.NetworkRegistrationInfo.Builder setIsNonTerrestrialNetwork(boolean); + method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setIsNonTerrestrialNetwork(boolean); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegisteredPlmn(@Nullable String); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int); method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int); @@ -16422,7 +16422,7 @@ package android.telephony.data { field public static final String TYPE_MMS_STRING = "mms"; field @FlaggedApi("com.android.internal.telephony.flags.oem_paid_private") public static final String TYPE_OEM_PAID_STRING = "oem_paid"; field @FlaggedApi("com.android.internal.telephony.flags.oem_paid_private") public static final String TYPE_OEM_PRIVATE_STRING = "oem_private"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final String TYPE_RCS_STRING = "rcs"; + field public static final String TYPE_RCS_STRING = "rcs"; field public static final String TYPE_SUPL_STRING = "supl"; field public static final String TYPE_VSIM_STRING = "vsim"; field public static final String TYPE_XCAP_STRING = "xcap"; @@ -18589,13 +18589,13 @@ package android.telephony.satellite { } @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") public final class SatelliteManager { - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatellite(@NonNull java.util.List<android.telephony.satellite.SatelliteSubscriberInfo>, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telephony.satellite.SatelliteManager.SatelliteException>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getAttachRestrictionReasonsForCarrier(int); + method @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getAttachRestrictionReasonsForCarrier(int); method @FlaggedApi("com.android.internal.telephony.flags.satellite_25q4_apis") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatelliteDataOptimizedApps(); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int[] getSatelliteDisallowedReasons(); - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatellitePlmnsForCarrier(int); + method @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatellitePlmnsForCarrier(int); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatellite(@NonNull java.util.List<android.telephony.satellite.SatelliteSubscriberInfo>, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telephony.satellite.SatelliteManager.SatelliteException>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); @@ -18608,11 +18608,11 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void registerForSatelliteDisallowedReasonsChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDisallowedReasonsCallback); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSelectedNbIotSatelliteSubscriptionChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSupportedStateChanged(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestEnabled(@NonNull android.telephony.satellite.EnableRequestAttributes, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsAttachEnabledForCarrier(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>); + method @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsAttachEnabledForCarrier(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsCommunicationAllowedForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsDemoModeEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsEmergencyModeEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>); @@ -18656,15 +18656,15 @@ package android.telephony.satellite { field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DISPLAY_MODE_OPENED = 2; // 0x2 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DISPLAY_MODE_UNKNOWN = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS = 1; // 0x1 - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911 = 2; // 0x2 + field public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911 = 2; // 0x2 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_EMTC_NTN = 3; // 0x3 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_NB_IOT_NTN = 1; // 0x1 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2; // 0x2 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4; // 0x4 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String PROPERTY_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT = "android.telephony.satellite.PROPERTY_SATELLITE_MANUAL_CONNECT_P2P_SUPPORT"; - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT = 2; // 0x2 - field @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1; // 0x1 + field public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT = 2; // 0x2 + field public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1; // 0x1 field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; // 0x7 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 85fdcff4a28f..4222c7c64672 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1916,6 +1916,10 @@ package android.hardware.soundtrigger { package android.hardware.usb { + public class UsbManager { + method public boolean isUvcGadgetSupportEnabled(); + } + public final class UsbPort { method @FlaggedApi("android.hardware.usb.flags.enable_is_mode_change_supported_api") @RequiresPermission(android.Manifest.permission.MANAGE_USB) public boolean isModeChangeSupported(); } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 252d23f69400..ee9c64f97382 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -292,13 +292,15 @@ import java.util.function.Consumer; * to the user, it must be completely restarted and restored to its previous state.</li> * </ul> * - * <p>The following diagram shows the important state paths of an Activity. + * <p>The following diagram shows the important state paths of an activity. * The square rectangles represent callback methods you can implement to - * perform operations when the Activity moves between states. The colored - * ovals are major states the Activity can be in.</p> + * perform operations when the activity moves between states. The colored + * ovals are major states the activity can be in.</p> * - * <p><img src="../../../images/activity_lifecycle.png" - * alt="State diagram for an Android Activity Lifecycle." border="0" /></p> + * <p><img class="invert" + * style="display: block; margin: auto;" + * src="../../../images/activity_lifecycle.png" + * alt="State diagram for the Android activity lifecycle." /></p> * * <p>There are three key loops you may be interested in monitoring within your * activity: @@ -505,7 +507,7 @@ import java.util.function.Consumer; * changes.</p> * * <p>Unless you specify otherwise, a configuration change (such as a change - * in screen orientation, language, input devices, etc) will cause your + * in screen orientation, language, input devices, etc.) will cause your * current activity to be <em>destroyed</em>, going through the normal activity * lifecycle process of {@link #onPause}, * {@link #onStop}, and {@link #onDestroy} as appropriate. If the activity @@ -1838,7 +1840,7 @@ public class Activity extends ContextThemeWrapper * * <p>You can call {@link #finish} from within this function, in * which case onDestroy() will be immediately called after {@link #onCreate} without any of the - * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc) + * rest of the activity lifecycle ({@link #onStart}, {@link #onResume}, {@link #onPause}, etc.) * executing. * * <p><em>Derived classes must call through to the super class's @@ -2132,7 +2134,7 @@ public class Activity extends ContextThemeWrapper * * <p>You can call {@link #finish} from within this function, in * which case {@link #onStop} will be immediately called after {@link #onStart} without the - * lifecycle transitions in-between ({@link #onResume}, {@link #onPause}, etc) executing. + * lifecycle transitions in-between ({@link #onResume}, {@link #onPause}, etc.) executing. * * <p><em>Derived classes must call through to the super class's * implementation of this method. If they do not, an exception will be diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index f63170aa159d..c765298035e0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -101,6 +101,7 @@ import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ProviderInfoList; import android.content.pm.ServiceInfo; +import android.content.pm.SystemFeaturesCache; import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; @@ -387,7 +388,7 @@ public final class ActivityThread extends ClientTransactionHandler @UnsupportedAppUsage private ContextImpl mSystemContext; @GuardedBy("this") - private ArrayList<WeakReference<ContextImpl>> mDisplaySystemUiContexts; + private ArrayList<WeakReference<Context>> mDisplaySystemUiContexts; @UnsupportedAppUsage static volatile IPackageManager sPackageManager; @@ -1342,6 +1343,10 @@ public final class ActivityThread extends ClientTransactionHandler ApplicationSharedMemory instance = ApplicationSharedMemory.fromFileDescriptor( applicationSharedMemoryFd, /* mutable= */ false); + if (android.content.pm.Flags.cacheSdkSystemFeatures()) { + SystemFeaturesCache.setInstance( + new SystemFeaturesCache(instance.readSystemFeaturesCache())); + } instance.closeFileDescriptor(); ApplicationSharedMemory.setInstance(instance); } @@ -3204,7 +3209,7 @@ public final class ActivityThread extends ClientTransactionHandler } @NonNull - public ContextImpl getSystemUiContext() { + public Context getSystemUiContext() { return getSystemUiContext(DEFAULT_DISPLAY); } @@ -3214,7 +3219,7 @@ public final class ActivityThread extends ClientTransactionHandler * @see ContextImpl#createSystemUiContext(ContextImpl, int) */ @NonNull - public ContextImpl getSystemUiContext(int displayId) { + public Context getSystemUiContext(int displayId) { synchronized (this) { if (mDisplaySystemUiContexts == null) { mDisplaySystemUiContexts = new ArrayList<>(); @@ -3222,7 +3227,7 @@ public final class ActivityThread extends ClientTransactionHandler mDisplaySystemUiContexts.removeIf(contextRef -> contextRef.refersTo(null)); - ContextImpl context = getSystemUiContextNoCreateLocked(displayId); + Context context = getSystemUiContextNoCreateLocked(displayId); if (context != null) { return context; } @@ -3233,9 +3238,20 @@ public final class ActivityThread extends ClientTransactionHandler } } + /** + * Creates a {@code SystemUiContext} for testing. + * <p> + * DO NOT use it in production code. + */ + @VisibleForTesting + @NonNull + public Context createSystemUiContextForTesting(int displayId) { + return ContextImpl.createSystemUiContext(getSystemContext(), displayId); + } + @Nullable @Override - public ContextImpl getSystemUiContextNoCreate() { + public Context getSystemUiContextNoCreate() { synchronized (this) { if (mDisplaySystemUiContexts == null) { return null; @@ -3246,9 +3262,9 @@ public final class ActivityThread extends ClientTransactionHandler @GuardedBy("this") @Nullable - private ContextImpl getSystemUiContextNoCreateLocked(int displayId) { + private Context getSystemUiContextNoCreateLocked(int displayId) { for (int i = 0; i < mDisplaySystemUiContexts.size(); i++) { - ContextImpl context = mDisplaySystemUiContexts.get(i).get(); + Context context = mDisplaySystemUiContexts.get(i).get(); if (context != null && context.getDisplayId() == displayId) { return context; } @@ -3267,7 +3283,8 @@ public final class ActivityThread extends ClientTransactionHandler public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { synchronized (this) { getSystemContext().installSystemApplicationInfo(info, classLoader); - getSystemUiContext().installSystemApplicationInfo(info, classLoader); + final ContextImpl sysUiContextImpl = ContextImpl.getImpl(getSystemUiContext()); + sysUiContextImpl.installSystemApplicationInfo(info, classLoader); // give ourselves a default profiler mProfiler = new Profiler(); @@ -4759,6 +4776,7 @@ public final class ActivityThread extends ClientTransactionHandler // frame. final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); transaction.hide(startingWindowLeash); + startingWindowLeash.release(); view.syncTransferSurfaceOnDraw(); diff --git a/core/java/android/app/ActivityThreadInternal.java b/core/java/android/app/ActivityThreadInternal.java index 72506b9fcdbb..70876da9183f 100644 --- a/core/java/android/app/ActivityThreadInternal.java +++ b/core/java/android/app/ActivityThreadInternal.java @@ -17,6 +17,7 @@ package android.app; import android.content.ComponentCallbacks2; +import android.content.Context; import java.util.ArrayList; @@ -28,7 +29,7 @@ import java.util.ArrayList; interface ActivityThreadInternal { ContextImpl getSystemContext(); - ContextImpl getSystemUiContextNoCreate(); + Context getSystemUiContextNoCreate(); boolean isInDensityCompatMode(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index f2e7e8513116..1ed64f9416c0 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -78,6 +78,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.SuspendDialogInfo; +import android.content.pm.SystemFeaturesCache; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; import android.content.pm.dex.ArtManager; @@ -803,16 +804,6 @@ public class ApplicationPackageManager extends PackageManager { @Override public Boolean recompute(HasSystemFeatureQuery query) { try { - // As an optimization, check first to see if the feature was defined at - // compile-time as either available or unavailable. - // TODO(b/203143243): Consider hoisting this optimization out of the cache - // after the trunk stable (build) flag has soaked and more features are - // defined at compile-time. - Boolean maybeHasSystemFeature = - RoSystemFeatures.maybeHasFeature(query.name, query.version); - if (maybeHasSystemFeature != null) { - return maybeHasSystemFeature.booleanValue(); - } return ActivityThread.currentActivityThread().getPackageManager(). hasSystemFeature(query.name, query.version); } catch (RemoteException e) { @@ -823,15 +814,28 @@ public class ApplicationPackageManager extends PackageManager { @Override public boolean hasSystemFeature(String name, int version) { + // We check for system features in the following order: + // * Build time-defined system features (constant, very efficient) + // * SDK-defined system features (cached at process start, very efficient) + // * IPC-retrieved system features (lazily cached, requires per-feature IPC) + // TODO(b/375000483): Refactor all of this logic, including flag queries, into + // the SystemFeaturesCache class after initial rollout and validation. + Boolean maybeHasSystemFeature = RoSystemFeatures.maybeHasFeature(name, version); + if (maybeHasSystemFeature != null) { + return maybeHasSystemFeature; + } + if (com.android.internal.os.Flags.applicationSharedMemoryEnabled() + && android.content.pm.Flags.cacheSdkSystemFeatures()) { + maybeHasSystemFeature = + SystemFeaturesCache.getInstance().maybeHasFeature(name, version); + if (maybeHasSystemFeature != null) { + return maybeHasSystemFeature; + } + } return mHasSystemFeatureCache.query(new HasSystemFeatureQuery(name, version)); } /** @hide */ - public void disableHasSystemFeatureCache() { - mHasSystemFeatureCache.disableLocal(); - } - - /** @hide */ public static void invalidateHasSystemFeatureCache() { mHasSystemFeatureCache.invalidateCache(); } diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java index 62a50dbbd6f7..f491e3d274db 100644 --- a/core/java/android/app/ConfigurationController.java +++ b/core/java/android/app/ConfigurationController.java @@ -169,7 +169,7 @@ class ConfigurationController { // Get theme outside of synchronization to avoid nested lock. final Resources.Theme systemTheme = mActivityThread.getSystemContext().getTheme(); - final ContextImpl systemUiContext = mActivityThread.getSystemUiContextNoCreate(); + final Context systemUiContext = mActivityThread.getSystemUiContextNoCreate(); final Resources.Theme systemUiTheme = systemUiContext != null ? systemUiContext.getTheme() : null; synchronized (mResourcesManager) { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index d8aa8b3df622..1a6e9b07067f 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -97,6 +97,7 @@ import android.util.Slog; import android.view.Display; import android.view.DisplayAdjustments; import android.view.autofill.AutofillManager.AutofillClient; +import android.window.SystemUiContext; import android.window.WindowContext; import android.window.WindowTokenClient; import android.window.WindowTokenClientController; @@ -2975,6 +2976,13 @@ class ContextImpl extends Context { if (display != null) { updateDeviceIdIfChanged(display.getDisplayId()); } + updateResourceOverlayConstraints(); + } + + private void updateResourceOverlayConstraints() { + if (mResources != null) { + mResources.getAssets().setOverlayConstraints(getDisplayId(), getDeviceId()); + } } @Override @@ -2987,9 +2995,11 @@ class ContextImpl extends Context { } } - return new ContextImpl(this, mMainThread, mPackageInfo, mParams, + final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams, mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName, mToken, mUser, mFlags, mClassLoader, null, deviceId, true); + context.updateResourceOverlayConstraints(); + return context; } @NonNull @@ -3284,6 +3294,7 @@ class ContextImpl extends Context { mDeviceId = updatedDeviceId; mAttributionSource = createAttributionSourceWithDeviceId(mAttributionSource, mDeviceId); notifyOnDeviceChangedListeners(updatedDeviceId); + updateResourceOverlayConstraints(); } } @@ -3477,15 +3488,28 @@ class ContextImpl extends Context { * {@link #createSystemContext(ActivityThread)}. * @param displayId The ID of the display where the UI is shown. */ - static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) { + static Context createSystemUiContext(ContextImpl systemContext, int displayId) { + // Step 1. Create a ContextImpl associated with its own resources. final WindowTokenClient token = new WindowTokenClient(); final ContextImpl context = systemContext.createWindowContextBase(token, displayId); - token.attachContext(context); + + // Step 2. Create a SystemUiContext to wrap the ContextImpl, which enables to listen to + // its config updates. + final Context systemUiContext; + if (com.android.window.flags.Flags.trackSystemUiContextBeforeWms()) { + systemUiContext = new SystemUiContext(context); + context.setOuterContext(systemUiContext); + } else { + systemUiContext = context; + } + token.attachContext(systemUiContext); + + // Step 3. Associate the SystemUiContext with the display specified with ID. WindowTokenClientController.getInstance().attachToDisplayContent(token, displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; context.mOwnsToken = true; - return context; + return systemUiContext; } @UnsupportedAppUsage @@ -3686,6 +3710,7 @@ class ContextImpl extends Context { mResourcesManager.setLocaleConfig(lc); } } + updateResourceOverlayConstraints(); } void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) { diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 4b1afa517122..01b2953362b5 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -146,6 +146,7 @@ interface IActivityTaskManager { int getFrontActivityScreenCompatMode(); void setFrontActivityScreenCompatMode(int mode); void setFocusedTask(int taskId); + boolean setTaskIsPerceptible(int taskId, boolean isPerceptible); boolean removeTask(int taskId); void removeAllVisibleRecentTasks(); List<ActivityManager.RunningTaskInfo> getTasks(int maxNum, boolean filterOnlyVisibleRecents, diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 5dca1c70a2e6..06047a42e70d 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -18,6 +18,7 @@ package android.app; import static android.annotation.Dimension.DP; import static android.app.Flags.evenlyDividedCallStyleActionLayout; +import static android.app.Flags.notificationsRedesignTemplates; import static android.app.admin.DevicePolicyResources.Drawables.Source.NOTIFICATION; import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED; import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON; @@ -818,7 +819,8 @@ public class Notification implements Parcelable R.layout.notification_2025_template_expanded_base, R.layout.notification_2025_template_heads_up_base, R.layout.notification_2025_template_header, - R.layout.notification_2025_template_conversation, + R.layout.notification_2025_template_collapsed_conversation, + R.layout.notification_2025_template_expanded_conversation, R.layout.notification_2025_template_collapsed_call, R.layout.notification_2025_template_expanded_call, R.layout.notification_2025_template_collapsed_messaging, @@ -5963,7 +5965,8 @@ public class Notification implements Parcelable || resId == getCompactHeadsUpBaseLayoutResource() || resId == getMessagingCompactHeadsUpLayoutResource() || resId == getCollapsedMessagingLayoutResource() - || resId == getCollapsedMediaLayoutResource()); + || resId == getCollapsedMediaLayoutResource() + || resId == getCollapsedConversationLayoutResource()); RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId); resetStandardTemplate(contentView); @@ -6001,8 +6004,7 @@ public class Notification implements Parcelable // Update margins to leave space for the top line (but not for headerless views like // HUNS, which use a different layout that already accounts for that). Templates that // have content that will be displayed under the small icon also use a different margin. - if (Flags.notificationsRedesignTemplates() - && !p.mHeaderless && !p.mSkipTopLineAlignment) { + if (Flags.notificationsRedesignTemplates() && !p.mHeaderless) { int margin = getContentMarginTop(mContext, R.dimen.notification_2025_content_margin_top); contentView.setViewLayoutMargin(R.id.notification_main_column, @@ -7673,12 +7675,18 @@ public class Notification implements Parcelable } } + // Note: In the 2025 redesign, we use two separate layouts for the collapsed and expanded + // version of conversations. See below. private int getConversationLayoutResource() { - if (Flags.notificationsRedesignTemplates()) { - return R.layout.notification_2025_template_conversation; - } else { - return R.layout.notification_template_material_conversation; - } + return R.layout.notification_template_material_conversation; + } + + private int getCollapsedConversationLayoutResource() { + return R.layout.notification_2025_template_collapsed_conversation; + } + + private int getExpandedConversationLayoutResource() { + return R.layout.notification_2025_template_expanded_conversation; } private int getCollapsedCallLayoutResource() { @@ -9462,7 +9470,7 @@ public class Notification implements Parcelable boolean hideRightIcons = viewType != StandardTemplateParams.VIEW_TYPE_NORMAL; boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY; boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT; - boolean isHeaderless = !isConversationLayout && isCollapsed; + boolean isLegacyHeaderless = !isConversationLayout && isCollapsed; //TODO (b/217799515): ensure mConversationTitle always returns the correct // conversationTitle, probably set mConversationTitle = conversationTitle after this @@ -9483,7 +9491,8 @@ public class Notification implements Parcelable } else { isOneToOne = !isGroupConversation(); } - if (isHeaderless && isOneToOne && TextUtils.isEmpty(conversationTitle)) { + if ((isLegacyHeaderless || notificationsRedesignTemplates()) + && isOneToOne && TextUtils.isEmpty(conversationTitle)) { conversationTitle = getOtherPersonName(); } @@ -9493,22 +9502,24 @@ public class Notification implements Parcelable .viewType(viewType) .highlightExpander(isConversationLayout) .hideProgress(true) - .title(isHeaderless ? conversationTitle : null) .text(null) .hideLeftIcon(isOneToOne) - .hideRightIcon(hideRightIcons || isOneToOne) - .headerTextSecondary(isHeaderless ? null : conversationTitle) - .skipTopLineAlignment(true); + .hideRightIcon(hideRightIcons || isOneToOne); + if (notificationsRedesignTemplates()) { + p.title(conversationTitle) + .hideAppName(isCollapsed); + } else { + p.title(isLegacyHeaderless ? conversationTitle : null) + .headerTextSecondary(isLegacyHeaderless ? null : conversationTitle); + } RemoteViews contentView = mBuilder.applyStandardTemplateWithActions( - isConversationLayout - ? mBuilder.getConversationLayoutResource() - : isCollapsed - ? mBuilder.getCollapsedMessagingLayoutResource() - : mBuilder.getExpandedMessagingLayoutResource(), + getMessagingLayoutResource(isConversationLayout, isCollapsed), p, bindResult); - if (isConversationLayout) { + if (isConversationLayout && !notificationsRedesignTemplates()) { + // Redesign note: This view is replaced by the `title`, which is handled normally. mBuilder.setTextViewColorPrimary(contentView, R.id.conversation_text, p); + // Redesign note: This special divider is no longer needed. mBuilder.setTextViewColorSecondary(contentView, R.id.app_name_divider, p); } @@ -9538,7 +9549,18 @@ public class Notification implements Parcelable contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsImportantConversation", isImportantConversation); } - if (isHeaderless) { + if (notificationsRedesignTemplates() && !isCollapsed) { + // Align the title to the app/small icon in the expanded form. In other layouts, + // this margin is added directly to the notification_main_column parent, but for + // messages we don't want the margin to be applied to the actual messaging + // content since it can contain icons that are displayed below the app icon. + Resources res = mBuilder.mContext.getResources(); + int marginStart = res.getDimensionPixelSize( + R.dimen.notification_2025_content_margin_start); + contentView.setViewLayoutMargin(R.id.title, + RemoteViews.MARGIN_START, marginStart, TypedValue.COMPLEX_UNIT_PX); + } + if (isLegacyHeaderless) { // Collapsed legacy messaging style has a 1-line limit. contentView.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1); } @@ -9549,6 +9571,33 @@ public class Notification implements Parcelable return contentView; } + private int getMessagingLayoutResource(boolean isConversationLayout, boolean isCollapsed) { + if (notificationsRedesignTemplates()) { + // Note: We eventually would like to use the same layouts for both conversations and + // regular messaging notifications. + if (isConversationLayout) { + if (isCollapsed) { + return mBuilder.getCollapsedConversationLayoutResource(); + } else { + return mBuilder.getExpandedConversationLayoutResource(); + } + } else { + if (isCollapsed) { + return mBuilder.getCollapsedMessagingLayoutResource(); + } else { + return mBuilder.getExpandedMessagingLayoutResource(); + } + } + + } else { + return isConversationLayout + ? mBuilder.getConversationLayoutResource() + : isCollapsed + ? mBuilder.getCollapsedMessagingLayoutResource() + : mBuilder.getExpandedMessagingLayoutResource(); + } + } + private CharSequence getKey(Person person) { return person == null ? null : person.getKey() == null ? person.getName() : person.getKey(); @@ -14676,7 +14725,6 @@ public class Notification implements Parcelable Icon mPromotedPicture; boolean mCallStyleActions; boolean mAllowTextWithProgress; - boolean mSkipTopLineAlignment; int mTitleViewId; int mTextViewId; @Nullable CharSequence mTitle; @@ -14702,7 +14750,6 @@ public class Notification implements Parcelable mPromotedPicture = null; mCallStyleActions = false; mAllowTextWithProgress = false; - mSkipTopLineAlignment = false; mTitleViewId = R.id.title; mTextViewId = R.id.text; mTitle = null; @@ -14769,11 +14816,6 @@ public class Notification implements Parcelable return this; } - public StandardTemplateParams skipTopLineAlignment(boolean skipTopLineAlignment) { - mSkipTopLineAlignment = skipTopLineAlignment; - return this; - } - final StandardTemplateParams hideSnoozeButton(boolean hideSnoozeButton) { this.mHideSnoozeButton = hideSnoozeButton; return this; diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 464bcc025d92..361532613047 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -122,7 +122,7 @@ public final class UiAutomation { private static final String LOG_TAG = UiAutomation.class.getSimpleName(); private static final boolean DEBUG = false; - private static final boolean VERBOSE = Build.IS_DEBUGGABLE; + private static final boolean VERBOSE = false; private static final int CONNECTION_ID_UNDEFINED = -1; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 08719fc549f8..500f7585b673 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -14200,6 +14200,9 @@ public class DevicePolicyManager { * <li>Manifest.permission.ACTIVITY_RECOGNITION</li> * <li>Manifest.permission.BODY_SENSORS</li> * </ul> + * On devices running {@link android.os.Build.VERSION_CODES#BAKLAVA}, the + * {@link android.health.connect.HealthPermissions} are also included in the + * restricted list. * <p> * A profile owner may not grant these permissions (i.e. call this method with any of the * permissions listed above and {@code grantState} of {@code #PERMISSION_GRANT_STATE_GRANTED}), diff --git a/core/java/android/app/backup/BackupRestoreEventLogger.java b/core/java/android/app/backup/BackupRestoreEventLogger.java index 112c5fd808ef..8bde3a5f2efa 100644 --- a/core/java/android/app/backup/BackupRestoreEventLogger.java +++ b/core/java/android/app/backup/BackupRestoreEventLogger.java @@ -34,9 +34,11 @@ import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Class to log B&R stats for each data type that is backed up and restored by the calling app. @@ -325,6 +327,21 @@ public final class BackupRestoreEventLogger { } } + /** @hide */ + public static String toString(DataTypeResult result) { + Objects.requireNonNull(result, "result cannot be null"); + StringBuilder string = new StringBuilder("type=").append(result.mDataType) + .append(", successCount=").append(result.mSuccessCount) + .append(", failCount=").append(result.mFailCount); + if (!result.mErrors.isEmpty()) { + string.append(", errors=").append(result.mErrors); + } + if (result.mMetadataHash != null) { + string.append(", metadataHash=").append(Arrays.toString(result.mMetadataHash)); + } + return string.toString(); + } + /** * Encapsulate logging results for a single data type. */ diff --git a/core/java/android/app/contextualsearch/flags.aconfig b/core/java/android/app/contextualsearch/flags.aconfig index bc1f7cea7fce..1de034b23a7a 100644 --- a/core/java/android/app/contextualsearch/flags.aconfig +++ b/core/java/android/app/contextualsearch/flags.aconfig @@ -24,7 +24,7 @@ flag { } flag { - name: "contextual_search_window_layer" + name: "contextual_search_prevent_self_capture" namespace: "sysui_integrations" description: "Identify live contextual search UI to exclude from contextual search screenshot." bug: "390176823" diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java index b4c293eeb695..7718d159896e 100644 --- a/core/java/android/app/jank/JankDataProcessor.java +++ b/core/java/android/app/jank/JankDataProcessor.java @@ -34,11 +34,13 @@ import java.util.List; /** * This class is responsible for associating frames received from SurfaceFlinger to active widget * states and logging those states back to the platform. + * * @hide */ @FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) public class JankDataProcessor { - + private static final String TAG = "JankDataProcessor"; + private static final boolean DEBUG_LOGGING = false; private static final int MAX_IN_MEMORY_STATS = 25; private static final int LOG_BATCH_FREQUENCY = 50; private int mCurrentBatchCount = 0; @@ -54,9 +56,10 @@ public class JankDataProcessor { /** * Called once per batch of JankData. - * @param jankData data received from SurfaceFlinger to be processed + * + * @param jankData data received from SurfaceFlinger to be processed * @param activityName name of the activity that is tracking jank metrics. - * @param appUid the uid of the app. + * @param appUid the uid of the app. */ public void processJankData(List<JankData> jankData, String activityName, int appUid) { // add all the previous and active states to the pending states list. @@ -211,8 +214,6 @@ public class JankDataProcessor { * clear any pending widget states. */ public void logMetricCounts() { - //TODO b/374607503 when api changes are in add enum mapping for category and state. - try { mPendingJankStats.values().forEach(stat -> { FrameworkStatsLog.write( @@ -221,15 +222,16 @@ public class JankDataProcessor { /*activity name*/ stat.getActivityName(), /*widget id*/ stat.getWidgetId(), /*refresh rate*/ stat.getRefreshRate(), - /*widget category*/ 0, - /*widget state*/ 0, + /*widget category*/ widgetCategoryToInt(stat.getWidgetCategory()), + /*widget state*/ widgetStateToInt(stat.getWidgetState()), /*total frames*/ stat.getTotalFrames(), /*janky frames*/ stat.getJankyFrames(), - /*histogram*/ stat.mFrameOverrunBuckets); + /*histogram*/ stat.getFrameOverrunBuckets()); Log.d(stat.mActivityName, stat.toString()); // return the pending stat to the pool it will be reset the next time its // used. mPendingJankStatsPool.release(stat); + } ); // All stats have been recorded and added back to the pool for reuse, clear the pending @@ -241,6 +243,96 @@ public class JankDataProcessor { } } + private int widgetCategoryToInt(String widgetCategory) { + switch (widgetCategory) { + case AppJankStats.WIDGET_CATEGORY_SCROLL -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SCROLLING; + } + case AppJankStats.WIDGET_CATEGORY_ANIMATION -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__ANIMATION; + } + case AppJankStats.WIDGET_CATEGORY_MEDIA -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__MEDIA; + } + case AppJankStats.WIDGET_CATEGORY_NAVIGATION -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__NAVIGATION; + } + case AppJankStats.WIDGET_CATEGORY_KEYBOARD -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__KEYBOARD; + } + case AppJankStats.WIDGET_CATEGORY_OTHER -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__OTHER; + } + default -> { + if (DEBUG_LOGGING) { + Log.d(TAG, "Default Category Logged: " + + AppJankStats.WIDGET_CATEGORY_UNSPECIFIED); + } + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_TYPE__WIDGET_CATEGORY_UNSPECIFIED; + } + } + } + + private int widgetStateToInt(String widgetState) { + switch (widgetState) { + case AppJankStats.WIDGET_STATE_NONE -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__NONE; + } + case AppJankStats.WIDGET_STATE_SCROLLING -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SCROLLING; + } + case AppJankStats.WIDGET_STATE_FLINGING -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__FLINGING; + } + case AppJankStats.WIDGET_STATE_SWIPING -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__SWIPING; + } + case AppJankStats.WIDGET_STATE_DRAGGING -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__DRAGGING; + } + case AppJankStats.WIDGET_STATE_ZOOMING -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__ZOOMING; + } + case AppJankStats.WIDGET_STATE_ANIMATING -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__ANIMATING; + } + case AppJankStats.WIDGET_STATE_PLAYBACK -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__PLAYBACK; + } + case AppJankStats.WIDGET_STATE_TAPPING -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__TAPPING; + } + case AppJankStats.WIDGET_STATE_PREDICTIVE_BACK -> { + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__PREDICTIVE_BACK; + } + default -> { + if (DEBUG_LOGGING) { + Log.d(TAG, "Default State Logged: " + + AppJankStats.WIDGET_STATE_UNSPECIFIED); + } + return FrameworkStatsLog + .JANK_FRAME_COUNT_BY_WIDGET_REPORTED__WIDGET_STATE__WIDGET_STATE_UNSPECIFIED; + } + } + } + public static final class PendingJankStat { private static final int NANOS_PER_MS = 1000000; public long processedVsyncId = -1; @@ -268,7 +360,7 @@ public class JankDataProcessor { private int mRefreshRate; - private static final int[] sFrameOverrunHistogramBounds = { + private static final int[] sFrameOverrunHistogramBounds = { Integer.MIN_VALUE, -200, -150, -100, -90, -80, -70, -60, -50, -40, -30, -25, -20, -18, -16, -14, -12, -10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 300, 400, 500, 600, 700, 800, 900, 1000, @@ -279,6 +371,7 @@ public class JankDataProcessor { // Histogram of frame duration overruns encoded in predetermined buckets. public PendingJankStat() { } + public long getProcessedVsyncId() { return processedVsyncId; } @@ -422,4 +515,4 @@ public class JankDataProcessor { } } -} +}
\ No newline at end of file diff --git a/core/java/android/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java index a04f96a9f6e3..9c85b09f6be3 100644 --- a/core/java/android/app/jank/JankTracker.java +++ b/core/java/android/app/jank/JankTracker.java @@ -20,6 +20,7 @@ import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.os.Handler; import android.os.HandlerThread; +import android.util.Log; import android.view.AttachedSurfaceControl; import android.view.Choreographer; import android.view.SurfaceControl; @@ -30,16 +31,22 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; /** * This class is responsible for registering callbacks that will receive JankData batches. * It handles managing the background thread that JankData will be processed on. As well as acting * as an intermediary between widgets and the state tracker, routing state changes to the tracker. + * * @hide */ @FlaggedApi(Flags.FLAG_DETAILED_APP_JANK_METRICS_API) public class JankTracker { - + private static final boolean DEBUG = false; + private static final String DEBUG_KEY = "JANKTRACKER"; + // How long to delay the JankData listener registration. + //TODO b/394956095 see if this can be reduced or eliminated. + private static final int REGISTRATION_DELAY_MS = 1000; // Tracks states reported by widgets. private StateTracker mStateTracker; // Processes JankData batches and associates frames to widget states. @@ -49,9 +56,6 @@ public class JankTracker { private HandlerThread mHandlerThread = new HandlerThread("AppJankTracker"); private Handler mHandler = null; - // Needed so we know when the view is attached to a window. - private ViewTreeObserver mViewTreeObserver; - // Handle to a registered OnJankData listener. private SurfaceControl.OnJankDataListenerRegistration mJankDataListenerRegistration; @@ -76,6 +80,40 @@ public class JankTracker { */ private boolean mListenersRegistered = false; + @FlaggedApi(com.android.window.flags.Flags.FLAG_JANK_API) + private final SurfaceControl.OnJankDataListener mJankDataListener = + new SurfaceControl.OnJankDataListener() { + @Override + public void onJankDataAvailable( + @androidx.annotation.NonNull List<SurfaceControl.JankData> jankData) { + if (mJankDataProcessor == null) return; + mJankDataProcessor.processJankData(jankData, mActivityName, mAppUid); + } + }; + + private final ViewTreeObserver.OnWindowAttachListener mOnWindowAttachListener = + new ViewTreeObserver.OnWindowAttachListener() { + @Override + public void onWindowAttached() { + getHandler().postDelayed(new Runnable() { + @Override + public void run() { + mDecorView.getViewTreeObserver() + .removeOnWindowAttachListener(mOnWindowAttachListener); + registerForJankData(); + } + }, REGISTRATION_DELAY_MS); + } + + // Leave this empty. Only need to know when the DecorView is attached to the Window + // in order to get a handle to AttachedSurfaceControl. There is no need to tie + // anything to when the view is detached as all un-registration code is tied to + // the lifecycle of the enclosing activity. + @Override + public void onWindowDetached() { + + } + }; public JankTracker(Choreographer choreographer, View decorView) { mStateTracker = new StateTracker(choreographer); @@ -108,9 +146,10 @@ public class JankTracker { /** * Will add the widget category, id and state as a UI state to associate frames to it. + * * @param widgetCategory preselected general widget category - * @param widgetId developer defined widget id if available. - * @param widgetState the current active widget state. + * @param widgetId developer defined widget id if available. + * @param widgetState the current active widget state. */ public void addUiState(String widgetCategory, String widgetId, String widgetState) { if (!shouldTrack()) return; @@ -121,9 +160,10 @@ public class JankTracker { /** * Will remove the widget category, id and state as a ui state and no longer attribute frames * to it. + * * @param widgetCategory preselected general widget category - * @param widgetId developer defined widget id if available. - * @param widgetState no longer active widget state. + * @param widgetId developer defined widget id if available. + * @param widgetState no longer active widget state. */ public void removeUiState(String widgetCategory, String widgetId, String widgetState) { if (!shouldTrack()) return; @@ -133,10 +173,11 @@ public class JankTracker { /** * Call to update a jank state to a different state. + * * @param widgetCategory preselected general widget category. - * @param widgetId developer defined widget id if available. - * @param currentState current state of the widget. - * @param nextState the state the widget will be in. + * @param widgetId developer defined widget id if available. + * @param currentState current state of the widget. + * @param nextState the state the widget will be in. */ public void updateUiState(String widgetCategory, String widgetId, String currentState, String nextState) { @@ -150,10 +191,11 @@ public class JankTracker { */ public void enableAppJankTracking() { // Add the activity as a state, this will ensure we track frames to the activity without the - // need of a decorated widget to be used. + // need for a decorated widget to be used. // TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged. mStateTracker.putState("NONE", mActivityName, "NONE"); mTrackingEnabled = true; + registerForJankData(); } /** @@ -163,10 +205,12 @@ public class JankTracker { mTrackingEnabled = false; // TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged. mStateTracker.removeState("NONE", mActivityName, "NONE"); + unregisterForJankData(); } /** * Retrieve all pending widget states, this is intended for testing purposes only. + * * @param stateDataList the ArrayList that will be populated with the pending states. */ @VisibleForTesting @@ -190,16 +234,35 @@ public class JankTracker { @VisibleForTesting public void forceListenerRegistration() { mSurfaceControl = mDecorView.getRootSurfaceControl(); - registerForJankData(); - // TODO b/376116199 Check if registration is good. - mListenersRegistered = true; + registerJankDataListener(); + } + + private void unregisterForJankData() { + if (mJankDataListenerRegistration == null) return; + + if (com.android.window.flags.Flags.jankApi()) { + mJankDataListenerRegistration.release(); + } + mJankDataListenerRegistration = null; + mListenersRegistered = false; } private void registerForJankData() { - if (mSurfaceControl == null) return; - /* - TODO b/376115668 Register for JankData batches from new JankTracking API - */ + if (mDecorView == null) return; + + mSurfaceControl = mDecorView.getRootSurfaceControl(); + + if (mSurfaceControl == null || mListenersRegistered) return; + + // Wait a short time before registering the listener. During development it was observed + // that if a listener is registered too quickly after a hot or warm start no data is + // received b/394956095. + getHandler().postDelayed(new Runnable() { + @Override + public void run() { + registerJankDataListener(); + } + }, REGISTRATION_DELAY_MS); } /** @@ -218,23 +281,30 @@ public class JankTracker { */ private void registerWindowListeners() { if (mDecorView == null) return; - mViewTreeObserver = mDecorView.getViewTreeObserver(); - mViewTreeObserver.addOnWindowAttachListener(new ViewTreeObserver.OnWindowAttachListener() { - @Override - public void onWindowAttached() { - getHandler().postDelayed(new Runnable() { - @Override - public void run() { - forceListenerRegistration(); - } - }, 1000); + mDecorView.getViewTreeObserver().addOnWindowAttachListener(mOnWindowAttachListener); + } + + private void registerJankDataListener() { + if (mSurfaceControl == null) { + if (DEBUG) { + Log.d(DEBUG_KEY, "SurfaceControl is Null"); } + return; + } - @Override - public void onWindowDetached() { - // TODO b/376116199 do we un-register the callback or just not process the data. + if (com.android.window.flags.Flags.jankApi()) { + mJankDataListenerRegistration = mSurfaceControl.registerOnJankDataListener( + mHandlerThread.getThreadExecutor(), mJankDataListener); + + if (mJankDataListenerRegistration + == SurfaceControl.OnJankDataListenerRegistration.NONE) { + if (DEBUG) { + Log.d(DEBUG_KEY, "OnJankDataListenerRegistration is assigned NONE"); + } + return; } - }); + mListenersRegistered = true; + } } private Handler getHandler() { diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index bb4f556532f7..8e6b88c66408 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -83,6 +83,13 @@ flag { } flag { + name: "modes_cleanup_implicit" + namespace: "systemui" + description: "Deletes implicit modes if never customized and not used for some time. Depends on MODES_UI" + bug: "394087495" +} + +flag { name: "api_tvextender" is_exported: true namespace: "systemui" diff --git a/core/java/android/app/supervision/ISupervisionManager.aidl b/core/java/android/app/supervision/ISupervisionManager.aidl index e583302e4d3b..2f67a8abcd17 100644 --- a/core/java/android/app/supervision/ISupervisionManager.aidl +++ b/core/java/android/app/supervision/ISupervisionManager.aidl @@ -16,11 +16,14 @@ package android.app.supervision; +import android.content.Intent; + /** * Internal IPC interface to the supervision service. * {@hide} */ interface ISupervisionManager { + Intent createConfirmSupervisionCredentialsIntent(); boolean isSupervisionEnabledForUser(int userId); void setSupervisionEnabledForUser(int userId, boolean enabled); String getActiveSupervisionAppPackage(int userId); diff --git a/core/java/android/app/supervision/SupervisionManager.java b/core/java/android/app/supervision/SupervisionManager.java index 6b7f4162d084..0270edf080a9 100644 --- a/core/java/android/app/supervision/SupervisionManager.java +++ b/core/java/android/app/supervision/SupervisionManager.java @@ -31,6 +31,7 @@ import android.annotation.UserIdInt; import android.app.supervision.flags.Flags; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.Intent; import android.os.RemoteException; /** @@ -83,6 +84,38 @@ public class SupervisionManager { } /** + * Creates an {@link Intent} that can be used with {@link Context#startActivity(Intent)} to + * launch the activity to verify supervision credentials. + * + * <p>A valid {@link Intent} is always returned if supervision is enabled at the time this API + * is called, the launched activity still need to perform validity checks as the supervision + * state can change when the activity is launched. A null intent is returned if supervision is + * disabled at the time of this API call. + * + * <p>A result code of {@link android.app.Activity#RESULT_OK} indicates successful verification + * of the supervision credentials. + * + * @hide + */ + @RequiresPermission(value = android.Manifest.permission.QUERY_USERS) + @Nullable + public Intent createConfirmSupervisionCredentialsIntent() { + if (mService != null) { + try { + Intent result = mService.createConfirmSupervisionCredentialsIntent(); + if (result != null) { + result.prepareToEnterProcess( + Intent.LOCAL_FLAG_FROM_SYSTEM, mContext.getAttributionSource()); + } + return result; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return null; + } + + /** * Returns whether the device is supervised. * * @hide diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS index 0e85d5bd7a27..1dc4cbb701fa 100644 --- a/core/java/android/appwidget/OWNERS +++ b/core/java/android/appwidget/OWNERS @@ -3,5 +3,4 @@ sihua@google.com pinyaoting@google.com suprabh@google.com sunnygoyal@google.com -zakcohen@google.com shamalip@google.com diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig index fcdb02ab5da2..67ade79e1b94 100644 --- a/core/java/android/companion/virtual/flags/flags.aconfig +++ b/core/java/android/companion/virtual/flags/flags.aconfig @@ -120,8 +120,26 @@ flag { } flag { + name: "correct_virtual_display_power_state" + namespace: "virtual_devices" + description: "Fix the virtual display power state" + bug: "371125136" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "vdm_settings" namespace: "virtual_devices" description: "Show virtual devices in Settings" bug: "338974320" } + +flag { + name: "migrate_viewconfiguration_constants_to_resources" + namespace: "virtual_devices" + description: "Use resources instead of constants in ViewConfiguration" + is_fixed_read_only: true + bug: "370928384" +} diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index d64ef75a8f7c..4bbbad4d1667 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -3250,7 +3250,6 @@ public class PackageInstaller { */ @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) - @FlaggedApi(Flags.FLAG_RECOVERABILITY_DETECTION) public void setRollbackImpactLevel(@PackageManager.RollbackImpactLevel int impactLevel) { if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) { throw new IllegalArgumentException( diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 6ae2df2cd7a2..9e91f5944504 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1619,7 +1619,6 @@ public abstract class PackageManager { * @hide */ @SystemApi - @FlaggedApi(android.content.pm.Flags.FLAG_RECOVERABILITY_DETECTION) public static final int ROLLBACK_USER_IMPACT_LOW = 0; /** @@ -1629,7 +1628,6 @@ public abstract class PackageManager { * @hide */ @SystemApi - @FlaggedApi(android.content.pm.Flags.FLAG_RECOVERABILITY_DETECTION) public static final int ROLLBACK_USER_IMPACT_HIGH = 1; /** @@ -1638,7 +1636,6 @@ public abstract class PackageManager { * @hide */ @SystemApi - @FlaggedApi(android.content.pm.Flags.FLAG_RECOVERABILITY_DETECTION) public static final int ROLLBACK_USER_IMPACT_ONLY_MANUAL = 2; /** @hide */ @@ -2041,7 +2038,7 @@ public abstract class PackageManager { public static final int INSTALL_SCENARIO_DEFAULT = 0; /** - * Installation scenario providing the fastest “install button to launch" experience possible. + * Installation scenario providing the fastest "install button to launch" experience possible. */ public static final int INSTALL_SCENARIO_FAST = 1; @@ -3588,7 +3585,7 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device is - * compatible with Android’s security model. + * compatible with Android's security model. * * <p>See sections 2 and 9 in the * <a href="https://source.android.com/compatibility/android-cdd">Android CDD</a> for more diff --git a/core/java/android/content/pm/SystemFeaturesCache.java b/core/java/android/content/pm/SystemFeaturesCache.java index c41a7abbbc35..b3d70fa8bfaf 100644 --- a/core/java/android/content/pm/SystemFeaturesCache.java +++ b/core/java/android/content/pm/SystemFeaturesCache.java @@ -16,9 +16,8 @@ package android.content.pm; +import android.annotation.MainThread; import android.annotation.NonNull; -import android.os.Parcel; -import android.os.Parcelable; import android.util.ArrayMap; import com.android.internal.annotations.VisibleForTesting; @@ -35,16 +34,53 @@ import java.util.Collection; * * @hide */ -public final class SystemFeaturesCache implements Parcelable { +public final class SystemFeaturesCache { // Sentinel value used for SDK-declared features that are unavailable on the current device. private static final int UNAVAILABLE_FEATURE_VERSION = Integer.MIN_VALUE; + // This will be initialized just once, from the process main thread, but ready from any thread. + private static volatile SystemFeaturesCache sInstance; + // An array of versions for SDK-defined features, from [0, PackageManager.SDK_FEATURE_COUNT). @NonNull private final int[] mSdkFeatureVersions; /** + * Installs the process-global cache instance. + * + * <p>Note: Usage should be gated on android.content.pm.Flags.cacheSdkSystemFeature(). In + * practice, this should only be called from 1) SystemServer init, or 2) bindApplication. + */ + @MainThread + public static void setInstance(SystemFeaturesCache instance) { + if (sInstance != null) { + throw new IllegalStateException("SystemFeaturesCache instance already initialized."); + } + sInstance = instance; + } + + /** + * Gets the process-global cache instance. + * + * Note: Usage should be gated on android.content.pm.Flags.cacheSdkSystemFeature(), and should + * always occur after the instance has been installed early in the process lifecycle. + */ + public static @NonNull SystemFeaturesCache getInstance() { + SystemFeaturesCache instance = sInstance; + if (instance == null) { + throw new IllegalStateException("SystemFeaturesCache not initialized"); + } + return instance; + } + + /** Clears the process-global cache instance for testing. */ + @VisibleForTesting + public static void clearInstance() { + sInstance = null; + } + + /** * Populates the cache from the set of all available {@link FeatureInfo} definitions. * * System features declared in {@link PackageManager} will be entered into the cache based on @@ -69,20 +105,28 @@ public final class SystemFeaturesCache implements Parcelable { } } - /** Only used by @{code CREATOR.createFromParcel(...)} */ - private SystemFeaturesCache(@NonNull Parcel parcel) { - final int[] featureVersions = parcel.createIntArray(); - if (featureVersions == null) { - throw new IllegalArgumentException( - "Parceled SDK feature versions should never be null"); - } - if (featureVersions.length != PackageManager.SDK_FEATURE_COUNT) { + /** + * Populates the cache from an array of SDK feature versions originally obtained via {@link + * #getSdkFeatureVersions()} from another instance. + */ + public SystemFeaturesCache(@NonNull int[] sdkFeatureVersions) { + if (sdkFeatureVersions.length != PackageManager.SDK_FEATURE_COUNT) { throw new IllegalArgumentException( String.format( "Unexpected cached SDK feature count: %d (expected %d)", - featureVersions.length, PackageManager.SDK_FEATURE_COUNT)); + sdkFeatureVersions.length, PackageManager.SDK_FEATURE_COUNT)); } - mSdkFeatureVersions = featureVersions; + mSdkFeatureVersions = sdkFeatureVersions; + } + + /** + * Gets the raw cached feature versions. + * + * <p>Note: This should generally only be neded for (de)serialization purposes. + */ + // TODO(b/375000483): Consider reusing the ApplicationSharedMemory mapping for version lookup. + public int[] getSdkFeatureVersions() { + return mSdkFeatureVersions; } /** @@ -105,29 +149,4 @@ public final class SystemFeaturesCache implements Parcelable { return mSdkFeatureVersions[sdkFeatureIndex] >= version; } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel parcel, int flags) { - parcel.writeIntArray(mSdkFeatureVersions); - } - - @NonNull - public static final Parcelable.Creator<SystemFeaturesCache> CREATOR = - new Parcelable.Creator<SystemFeaturesCache>() { - - @Override - public SystemFeaturesCache createFromParcel(Parcel parcel) { - return new SystemFeaturesCache(parcel); - } - - @Override - public SystemFeaturesCache[] newArray(int size) { - return new SystemFeaturesCache[size]; - } - }; } diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig index e4b8c90d381d..255a08cf170f 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -391,3 +391,12 @@ flag { bug: "319137634" is_fixed_read_only: true } + +flag { + name: "always_load_past_certs_v4" + is_exported: true + namespace: "package_manager_service" + description: "Always read the corresponding v3/3.1 signature block for the current v4 to get the past rotated certificates, even when not verifying integrity." + bug: "378539511" + is_fixed_read_only: true +} diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 7cd2d31ac974..bcb50881d327 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -148,8 +148,8 @@ public final class AssetManager implements AutoCloseable { * @hide */ public static class Builder { - private ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>(); - private ArrayList<ResourcesLoader> mLoaders = new ArrayList<>(); + private final ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>(); + private final ArrayList<ResourcesLoader> mLoaders = new ArrayList<>(); private boolean mNoInit = false; @@ -1625,6 +1625,23 @@ public final class AssetManager implements AutoCloseable { } /** + * Passes the display id and device id to AssetManager, to filter out overlays based on + * any {@link android.content.om.OverlayConstraint}. + * + * @hide + */ + public void setOverlayConstraints(int displayId, int deviceId) { + if (!Flags.rroConstraints()) { + return; + } + + synchronized (this) { + ensureValidLocked(); + nativeSetOverlayConstraints(mObject, displayId, deviceId); + } + } + + /** * @hide */ @UnsupportedAppUsage @@ -1717,6 +1734,7 @@ public final class AssetManager implements AutoCloseable { int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender, int majorVersion, boolean forceRefresh); + private static native void nativeSetOverlayConstraints(long ptr, int displayId, int deviceId); private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers( long ptr, boolean includeOverlays, boolean includeLoaders); diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index ef200c328d63..2e0999410483 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -2358,8 +2358,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration * @param locales The locale list. If null, an empty LocaleList will be assigned. */ public void setLocales(@Nullable LocaleList locales) { + LocaleList oldList = mLocaleList; mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales; locale = mLocaleList.get(0); + if (!mLocaleList.equals(oldList)) { + Slog.v(TAG, "Updating configuration, locales updated from " + oldList + + " to " + mLocaleList); + } setLayoutDirection(locale); } diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 96c71765d102..eec30f38b415 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -491,6 +491,9 @@ public class ResourcesImpl { } defaultLocale = adjustLanguageTag(lc.getDefaultLocale().toLanguageTag()); + Slog.v(TAG, "Updating configuration, with default locale " + + defaultLocale + " and selected locales " + + Arrays.toString(selectedLocales)); } else { String[] availableLocales; // The LocaleList has changed. We must query the AssetManager's @@ -526,6 +529,7 @@ public class ResourcesImpl { for (int i = 0; i < locales.size(); i++) { selectedLocales[i] = adjustLanguageTag(locales.get(i).toLanguageTag()); } + defaultLocale = adjustLanguageTag(lc.getDefaultLocale().toLanguageTag()); } else { selectedLocales = new String[]{ adjustLanguageTag(locales.get(0).toLanguageTag())}; diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java index 40c532498fbc..36fa05905814 100644 --- a/core/java/android/content/res/XmlBlock.java +++ b/core/java/android/content/res/XmlBlock.java @@ -29,6 +29,8 @@ import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.TypedValue; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.pm.pkg.component.AconfigFlags; +import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; import com.android.internal.util.XmlUtils; import dalvik.annotation.optimization.CriticalNative; @@ -50,6 +52,7 @@ import java.io.Reader; @RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public final class XmlBlock implements AutoCloseable { private static final boolean DEBUG=false; + public static final String ANDROID_RESOURCES = "http://schemas.android.com/apk/res/android"; @UnsupportedAppUsage public XmlBlock(byte[] data) { @@ -343,6 +346,23 @@ public final class XmlBlock implements AutoCloseable { if (ev == ERROR_BAD_DOCUMENT) { throw new XmlPullParserException("Corrupt XML binary file"); } + if (useLayoutReadwrite() && ev == START_TAG) { + AconfigFlags flags = ParsingPackageUtils.getAconfigFlags(); + if (flags.skipCurrentElement(/* pkg= */ null, this)) { + int depth = 1; + while (depth > 0) { + int ev2 = nativeNext(mParseState); + if (ev2 == ERROR_BAD_DOCUMENT) { + throw new XmlPullParserException("Corrupt XML binary file"); + } else if (ev2 == START_TAG) { + depth++; + } else if (ev2 == END_TAG) { + depth--; + } + } + return next(); + } + } if (mDecNextDepth) { mDepth--; mDecNextDepth = false; @@ -368,6 +388,18 @@ public final class XmlBlock implements AutoCloseable { } return ev; } + + // Until ravenwood supports AconfigFlags, we just don't do layoutReadwriteFlags(). + @android.ravenwood.annotation.RavenwoodReplace( + bug = 396458006, blockedBy = AconfigFlags.class) + private static boolean useLayoutReadwrite() { + return Flags.layoutReadwriteFlags(); + } + + private static boolean useLayoutReadwrite$ravenwood() { + return false; + } + public void require(int type, String namespace, String name) throws XmlPullParserException,IOException { if (type != getEventType() || (namespace != null && !namespace.equals( getNamespace () ) ) diff --git a/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl index eb1255c06094..5e6bb2d434d5 100644 --- a/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl +++ b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl @@ -99,5 +99,5 @@ interface IContextHubEndpoint { * Invoked when a callback from IContextHubEndpointCallback finishes. */ @EnforcePermission("ACCESS_CONTEXT_HUB") - void onCallbackFinished(); + oneway void onCallbackFinished(); } diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl index bb5491d98cf9..71870344eda3 100644 --- a/core/java/android/hardware/location/IContextHubService.aidl +++ b/core/java/android/hardware/location/IContextHubService.aidl @@ -153,5 +153,5 @@ interface IContextHubService { // Called when a discovery callback is finished executing @EnforcePermission("ACCESS_CONTEXT_HUB") - void onDiscoveryCallbackFinished(); + oneway void onDiscoveryCallbackFinished(); } diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl index c0e506b05a64..21d3ef0ea660 100644 --- a/core/java/android/hardware/usb/IUsbManager.aidl +++ b/core/java/android/hardware/usb/IUsbManager.aidl @@ -126,6 +126,9 @@ interface IUsbManager /* Returns true if the specified USB function is enabled. */ boolean isFunctionEnabled(String function); + /* Returns true if UVC gadget support is enabled. */ + boolean isUvcGadgetSupportEnabled(); + /* Sets the current USB function. */ @EnforcePermission("MANAGE_USB") void setCurrentFunctions(long functions, int operationId); diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index d2e232a94622..a005e334f402 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -30,8 +30,10 @@ import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -1437,6 +1439,21 @@ public class UsbManager { } /** + * Returns true if the specified UVC gadget function support is enabled. + * <p> + * @hide + */ + @TestApi + @SuppressLint("UnflaggedApi") // @TestApi without associated feature. + public boolean isUvcGadgetSupportEnabled() { + try { + return mService.isUvcGadgetSupportEnabled(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Sets the current USB functions when in device mode. * <p> * USB functions represent interfaces which are published to the host to access @@ -1641,6 +1658,7 @@ public class UsbManager { } } + // TODO: b/396680593 Deprecate to de-dup with isUvcGadgetSupportEnabled() /** * Returns whether UVC is advertised to be supported or not. SELinux * enforces that this function returns {@code false} when called from a diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index a528ba4b16bf..7b47efd47008 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -990,6 +990,8 @@ public class InputMethodService extends AbstractInputMethodService { } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); if (android.view.inputmethod.Flags.refactorInsetsController()) { + // After the IME window was hidden, we can remove its surface + scheduleImeSurfaceRemoval(); // The hide request first finishes the animation and then proceeds to the server // side, finally reaching here, marking this the end state. ImeTracker.forLogging().onHidden(statsToken); diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 349a2f0a181d..3c03bb5626c8 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -178,11 +178,6 @@ public final class MessageQueue { // We can lift these restrictions in the future after we've made it possible for test // authors to test Looper and MessageQueue without resorting to reflection. - - // Holdback study. - if (sIsProcessAllowedToUseConcurrent && Flags.messageQueueForceLegacy()) { - sIsProcessAllowedToUseConcurrent = false; - } } @RavenwoodReplace @@ -238,9 +233,13 @@ public final class MessageQueue { traceMessageCount(); PerfettoTrace.instant(PerfettoTrace.MQ_CATEGORY, "message_queue_send") .addFlow(msg.mEventId.get()) - .addArg("receiving_thread", mThread.getName()) - .addArg("delay", when - SystemClock.uptimeMillis()) - .addArg("what", msg.what) + .beginProto() + .beginNested(2004 /* message_queue */) + .addField(2 /* receiving_thread_name */, mThread.getName()) + .addField(3 /* message_code */, msg.what) + .addField(4 /* message_delay_ms */, when - SystemClock.uptimeMillis()) + .endNested() + .endProto() .emit(); } diff --git a/core/java/android/os/LockedMessageQueue/MessageQueue.java b/core/java/android/os/LockedMessageQueue/MessageQueue.java deleted file mode 100644 index 2401f3d11bcf..000000000000 --- a/core/java/android/os/LockedMessageQueue/MessageQueue.java +++ /dev/null @@ -1,1364 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.TestApi; -import android.compat.annotation.UnsupportedAppUsage; -import android.ravenwood.annotation.RavenwoodKeepWholeClass; -import android.ravenwood.annotation.RavenwoodRedirect; -import android.ravenwood.annotation.RavenwoodRedirectionClass; -import android.util.Log; -import android.util.Printer; -import android.util.SparseArray; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.GuardedBy; - -import dalvik.annotation.optimization.NeverCompile; - -import java.io.FileDescriptor; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Low-level class holding the list of messages to be dispatched by a - * {@link Looper}. Messages are not added directly to a MessageQueue, - * but rather through {@link Handler} objects associated with the Looper. - * - * <p>You can retrieve the MessageQueue for the current thread with - * {@link Looper#myQueue() Looper.myQueue()}. - */ -@RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("MessageQueue_ravenwood") -public final class MessageQueue { - private static final String TAG = "LockedMessageQueue"; - private static final boolean DEBUG = false; - private static final boolean TRACE = false; - - static final class MessageHeap { - static final int MESSAGE_HEAP_INITIAL_SIZE = 16; - - Message[] mHeap = new Message[MESSAGE_HEAP_INITIAL_SIZE]; - int mNumElements = 0; - - static int parentNodeIdx(int i) { - return (i - 1) >>> 1; - } - - Message getParentNode(int i) { - return mHeap[(i - 1) >>> 1]; - } - - static int rightNodeIdx(int i) { - return 2 * i + 2; - } - - Message getRightNode(int i) { - return mHeap[2 * i + 2]; - } - - static int leftNodeIdx(int i) { - return 2 * i + 1; - } - - Message getLeftNode(int i) { - return mHeap[2 * i + 1]; - } - - int size() { - return mHeap.length; - } - - int numElements() { - return mNumElements; - } - - boolean isEmpty() { - return mNumElements == 0; - } - - Message getMessageAt(int index) { - return mHeap[index]; - } - - /* - * Returns: - * 0 if x==y. - * A value less than 0 if x<y. - * A value greater than 0 if x>y. - */ - int compareMessage(Message x, Message y) { - int compared = Long.compare(x.when, y.when); - if (compared == 0) { - compared = Long.compare(x.mInsertSeq, y.mInsertSeq); - } - return compared; - } - - int compareMessageByIdx(int x, int y) { - return compareMessage(mHeap[x], mHeap[y]); - } - - void swap(int x, int y) { - Message tmp = mHeap[x]; - mHeap[x] = mHeap[y]; - mHeap[y] = tmp; - } - - void siftDown(int i) { - int smallest = i; - int r, l; - - while (true) { - r = rightNodeIdx(i); - l = leftNodeIdx(i); - - if (r < mNumElements && compareMessageByIdx(r, smallest) < 0) { - smallest = r; - } - - if (l < mNumElements && compareMessageByIdx(l, smallest) < 0) { - smallest = l; - } - - if (smallest != i) { - swap(i, smallest); - i = smallest; - continue; - } - break; - } - } - - boolean siftUp(int i) { - boolean swapped = false; - while (i != 0 && compareMessage(mHeap[i], getParentNode(i)) < 0) { - int p = parentNodeIdx(i); - - swap(i, p); - swapped = true; - i = p; - } - - return swapped; - } - - void maybeGrowHeap() { - if (mNumElements == mHeap.length) { - /* Grow by 1.5x */ - int newSize = mHeap.length + (mHeap.length >>> 1); - Message[] newHeap; - if (DEBUG) { - Log.v(TAG, "maybeGrowHeap mNumElements " + mNumElements + " mHeap.length " - + mHeap.length + " newSize " + newSize); - } - - newHeap = Arrays.copyOf(mHeap, newSize); - mHeap = newHeap; - } - } - - void add(Message m) { - int i; - - maybeGrowHeap(); - - i = mNumElements; - mNumElements++; - mHeap[i] = m; - - siftUp(i); - } - - void maybeShrinkHeap() { - /* Shrink by 2x */ - int newSize = mHeap.length >>> 1; - - if (newSize >= MESSAGE_HEAP_INITIAL_SIZE - && mNumElements <= newSize) { - Message[] newHeap; - - if (DEBUG) { - Log.v(TAG, "maybeShrinkHeap mNumElements " + mNumElements + " mHeap.length " - + mHeap.length + " newSize " + newSize); - } - - newHeap = Arrays.copyOf(mHeap, newSize); - mHeap = newHeap; - } - } - - Message poll() { - if (mNumElements > 0) { - Message ret = mHeap[0]; - mNumElements--; - mHeap[0] = mHeap[mNumElements]; - mHeap[mNumElements] = null; - - siftDown(0); - - maybeShrinkHeap(); - return ret; - } - return null; - } - - Message peek() { - if (mNumElements > 0) { - return mHeap[0]; - } - return null; - } - - private void remove(int i) throws IllegalArgumentException { - if (i > mNumElements || mNumElements == 0) { - throw new IllegalArgumentException("Index " + i + " out of bounds: " - + mNumElements); - } else if (i == (mNumElements - 1)) { - mHeap[i] = null; - mNumElements--; - } else { - mNumElements--; - mHeap[i] = mHeap[mNumElements]; - mHeap[mNumElements] = null; - if (!siftUp(i)) { - siftDown(i); - } - } - /* Don't shink here, let the caller do this once it has removed all matching items. */ - } - - void removeAll() { - Message m; - for (int i = 0; i < mNumElements; i++) { - m = mHeap[i]; - mHeap[i] = null; - m.recycleUnchecked(); - } - mNumElements = 0; - maybeShrinkHeap(); - } - - abstract static class MessageHeapCompare { - public abstract boolean compareMessage(Message m, Handler h, int what, Object object, - Runnable r, long when); - } - - boolean findOrRemoveMessages(Handler h, int what, Object object, Runnable r, long when, - MessageHeapCompare compare, boolean removeMatches) { - boolean found = false; - /* - * Walk the heap backwards so we don't have to re-visit an array element due to - * sifting - */ - for (int i = mNumElements - 1; i >= 0; i--) { - if (compare.compareMessage(mHeap[i], h, what, object, r, when)) { - found = true; - if (removeMatches) { - Message m = mHeap[i]; - try { - remove(i); - } catch (IllegalArgumentException e) { - Log.wtf(TAG, "Index out of bounds during remove " + e); - } - m.recycleUnchecked(); - continue; - } - break; - } - } - if (found && removeMatches) { - maybeShrinkHeap(); - } - return found; - } - - /* - * Keep this for manual debugging. It's easier to pepper the code with this function - * than MessageQueue.dump() - */ - @NeverCompile - void print() { - Log.v(TAG, "heap num elem: " + mNumElements + " mHeap.length " + mHeap.length); - for (int i = 0; i < mNumElements; i++) { - Log.v(TAG, "[" + i + "]\t" + mHeap[i] + " seq: " + mHeap[i].mInsertSeq + " async: " - + mHeap[i].isAsynchronous()); - } - } - - boolean verify(int root) { - int r = rightNodeIdx(root); - int l = leftNodeIdx(root); - - if (l >= mNumElements && r >= mNumElements) { - return true; - } - - if (l < mNumElements && compareMessageByIdx(l, root) < 0) { - Log.wtf(TAG, "Verify failure: root idx/when: " + root + "/" + mHeap[root].when - + " left node idx/when: " + l + "/" + mHeap[l].when); - return false; - } - - if (r < mNumElements && compareMessageByIdx(r, root) < 0) { - Log.wtf(TAG, "Verify failure: root idx/when: " + root + "/" + mHeap[root].when - + " right node idx/when: " + r + "/" + mHeap[r].when); - return false; - } - - if (!verify(r) || !verify(l)) { - return false; - } - return true; - } - - boolean checkDanglingReferences(String where) { - /* First, let's make sure we didn't leave any dangling references */ - for (int i = mNumElements; i < mHeap.length; i++) { - if (mHeap[i] != null) { - Log.wtf(TAG, "[" + where - + "] Verify failure: dangling reference found at index " - + i + ": " + mHeap[i] + " Async " + mHeap[i].isAsynchronous() - + " mNumElements " + mNumElements + " mHeap.length " + mHeap.length); - return false; - } - } - return true; - } - - boolean verify() { - if (!checkDanglingReferences(TAG)) { - return false; - } - return verify(0); - } - } - - // True if the message queue can be quit. - @UnsupportedAppUsage - private final boolean mQuitAllowed; - - @UnsupportedAppUsage - @SuppressWarnings("unused") - private long mPtr; // used by native code - - private final MessageHeap mPriorityQueue = new MessageHeap(); - private final MessageHeap mAsyncPriorityQueue = new MessageHeap(); - - /* - * This helps us ensure that messages with the same timestamp are inserted in FIFO order. - * Increments on each insert, starting at 0. MessaeHeap.compareMessage() will compare sequences - * when delivery timestamps are identical. - */ - private long mNextInsertSeq; - - /* - * The exception to the FIFO order rule is sendMessageAtFrontOfQueue(). - * Those messages must be in LIFO order. - * Decrements on each front of queue insert. - */ - private long mNextFrontInsertSeq = -1; - - @UnsupportedAppUsage - private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); - private SparseArray<FileDescriptorRecord> mFileDescriptorRecords; - private IdleHandler[] mPendingIdleHandlers; - private boolean mQuitting; - - // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. - private boolean mBlocked; - - // The next barrier token. - // Barriers are indicated by messages with a null target whose arg1 field carries the token. - @UnsupportedAppUsage - private int mNextBarrierToken; - - @RavenwoodRedirect - private native static long nativeInit(); - @RavenwoodRedirect - private native static void nativeDestroy(long ptr); - @UnsupportedAppUsage - @RavenwoodRedirect - private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/ - @RavenwoodRedirect - private native static void nativeWake(long ptr); - @RavenwoodRedirect - private native static boolean nativeIsPolling(long ptr); - @RavenwoodRedirect - private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events); - - MessageQueue(boolean quitAllowed) { - mQuitAllowed = quitAllowed; - mPtr = nativeInit(); - } - - @GuardedBy("this") - private void removeRootFromPriorityQueue(Message msg) { - Message tmp; - if (msg.isAsynchronous()) { - tmp = mAsyncPriorityQueue.poll(); - } else { - tmp = mPriorityQueue.poll(); - } - if (DEBUG && tmp != msg) { - Log.wtf(TAG, "Unexpected message at head of heap. Wanted: " + msg + " msg.isAsync " - + msg.isAsynchronous() + " Found: " + tmp); - - mPriorityQueue.print(); - mAsyncPriorityQueue.print(); - } - } - - @GuardedBy("this") - private Message pickEarliestMessage(Message x, Message y) { - if (x != null && y != null) { - if (mPriorityQueue.compareMessage(x, y) < 0) { - return x; - } - return y; - } - - return x != null ? x : y; - } - - @GuardedBy("this") - private Message peekEarliestMessage() { - Message x = mPriorityQueue.peek(); - Message y = mAsyncPriorityQueue.peek(); - - return pickEarliestMessage(x, y); - } - - @GuardedBy("this") - private boolean priorityQueuesAreEmpty() { - return mPriorityQueue.isEmpty() && mAsyncPriorityQueue.isEmpty(); - } - - @GuardedBy("this") - private boolean priorityQueueHasBarrier() { - Message m = mPriorityQueue.peek(); - - if (m != null && m.target == null) { - return true; - } - return false; - } - - @Override - protected void finalize() throws Throwable { - try { - dispose(); - } finally { - super.finalize(); - } - } - - // Disposes of the underlying message queue. - // Must only be called on the looper thread or the finalizer. - private void dispose() { - if (mPtr != 0) { - nativeDestroy(mPtr); - mPtr = 0; - } - } - - /** - * Returns true if the looper has no pending messages which are due to be processed. - * - * <p>This method is safe to call from any thread. - * - * @return True if the looper is idle. - */ - public boolean isIdle() { - synchronized (this) { - Message m = peekEarliestMessage(); - final long now = SystemClock.uptimeMillis(); - - return (priorityQueuesAreEmpty() || now < m.when); - } - } - - /** - * Add a new {@link IdleHandler} to this message queue. This may be - * removed automatically for you by returning false from - * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is - * invoked, or explicitly removing it with {@link #removeIdleHandler}. - * - * <p>This method is safe to call from any thread. - * - * @param handler The IdleHandler to be added. - */ - public void addIdleHandler(@NonNull IdleHandler handler) { - if (handler == null) { - throw new NullPointerException("Can't add a null IdleHandler"); - } - synchronized (this) { - mIdleHandlers.add(handler); - } - } - - /** - * Remove an {@link IdleHandler} from the queue that was previously added - * with {@link #addIdleHandler}. If the given object is not currently - * in the idle list, nothing is done. - * - * <p>This method is safe to call from any thread. - * - * @param handler The IdleHandler to be removed. - */ - public void removeIdleHandler(@NonNull IdleHandler handler) { - synchronized (this) { - mIdleHandlers.remove(handler); - } - } - - /** - * Returns whether this looper's thread is currently polling for more work to do. - * This is a good signal that the loop is still alive rather than being stuck - * handling a callback. Note that this method is intrinsically racy, since the - * state of the loop can change before you get the result back. - * - * <p>This method is safe to call from any thread. - * - * @return True if the looper is currently polling for events. - * @hide - */ - public boolean isPolling() { - synchronized (this) { - return isPollingLocked(); - } - } - - private boolean isPollingLocked() { - // If the loop is quitting then it must not be idling. - // We can assume mPtr != 0 when mQuitting is false. - return !mQuitting && nativeIsPolling(mPtr); - } - - /** - * Adds a file descriptor listener to receive notification when file descriptor - * related events occur. - * <p> - * If the file descriptor has already been registered, the specified events - * and listener will replace any that were previously associated with it. - * It is not possible to set more than one listener per file descriptor. - * </p><p> - * It is important to always unregister the listener when the file descriptor - * is no longer of use. - * </p> - * - * @param fd The file descriptor for which a listener will be registered. - * @param events The set of events to receive: a combination of the - * {@link OnFileDescriptorEventListener#EVENT_INPUT}, - * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and - * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested - * set of events is zero, then the listener is unregistered. - * @param listener The listener to invoke when file descriptor events occur. - * - * @see OnFileDescriptorEventListener - * @see #removeOnFileDescriptorEventListener - */ - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) - public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd, - @OnFileDescriptorEventListener.Events int events, - @NonNull OnFileDescriptorEventListener listener) { - if (fd == null) { - throw new IllegalArgumentException("fd must not be null"); - } - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - - synchronized (this) { - updateOnFileDescriptorEventListenerLocked(fd, events, listener); - } - } - - /** - * Removes a file descriptor listener. - * <p> - * This method does nothing if no listener has been registered for the - * specified file descriptor. - * </p> - * - * @param fd The file descriptor whose listener will be unregistered. - * - * @see OnFileDescriptorEventListener - * @see #addOnFileDescriptorEventListener - */ - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) - public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) { - if (fd == null) { - throw new IllegalArgumentException("fd must not be null"); - } - - synchronized (this) { - updateOnFileDescriptorEventListenerLocked(fd, 0, null); - } - } - - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) - private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events, - OnFileDescriptorEventListener listener) { - final int fdNum = fd.getInt$(); - - int index = -1; - FileDescriptorRecord record = null; - if (mFileDescriptorRecords != null) { - index = mFileDescriptorRecords.indexOfKey(fdNum); - if (index >= 0) { - record = mFileDescriptorRecords.valueAt(index); - if (record != null && record.mEvents == events) { - return; - } - } - } - - if (events != 0) { - events |= OnFileDescriptorEventListener.EVENT_ERROR; - if (record == null) { - if (mFileDescriptorRecords == null) { - mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>(); - } - record = new FileDescriptorRecord(fd, events, listener); - mFileDescriptorRecords.put(fdNum, record); - } else { - record.mListener = listener; - record.mEvents = events; - record.mSeq += 1; - } - nativeSetFileDescriptorEvents(mPtr, fdNum, events); - } else if (record != null) { - record.mEvents = 0; - mFileDescriptorRecords.removeAt(index); - nativeSetFileDescriptorEvents(mPtr, fdNum, 0); - } - } - - // Called from native code. - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private int dispatchEvents(int fd, int events) { - // Get the file descriptor record and any state that might change. - final FileDescriptorRecord record; - final int oldWatchedEvents; - final OnFileDescriptorEventListener listener; - final int seq; - synchronized (this) { - record = mFileDescriptorRecords.get(fd); - if (record == null) { - return 0; // spurious, no listener registered - } - - oldWatchedEvents = record.mEvents; - events &= oldWatchedEvents; // filter events based on current watched set - if (events == 0) { - return oldWatchedEvents; // spurious, watched events changed - } - - listener = record.mListener; - seq = record.mSeq; - } - - // Invoke the listener outside of the lock. - int newWatchedEvents = listener.onFileDescriptorEvents( - record.mDescriptor, events); - if (newWatchedEvents != 0) { - newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR; - } - - // Update the file descriptor record if the listener changed the set of - // events to watch and the listener itself hasn't been updated since. - if (newWatchedEvents != oldWatchedEvents) { - synchronized (this) { - int index = mFileDescriptorRecords.indexOfKey(fd); - if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record - && record.mSeq == seq) { - record.mEvents = newWatchedEvents; - if (newWatchedEvents == 0) { - mFileDescriptorRecords.removeAt(index); - } - } - } - } - - // Return the new set of events to watch for native code to take care of. - return newWatchedEvents; - } - - private static final AtomicLong mMessagesDelivered = new AtomicLong(); - - @UnsupportedAppUsage - Message next() { - // Return here if the message loop has already quit and been disposed. - // This can happen if the application tries to restart a looper after quit - // which is not supported. - final long ptr = mPtr; - if (ptr == 0) { - return null; - } - - int pendingIdleHandlerCount = -1; // -1 only during first iteration - int nextPollTimeoutMillis = 0; - for (;;) { - if (nextPollTimeoutMillis != 0) { - Binder.flushPendingCommands(); - } - - nativePollOnce(ptr, nextPollTimeoutMillis); - - synchronized (this) { - // Try to retrieve the next message. Return if found. - final long now = SystemClock.uptimeMillis(); - Message prevMsg = null; - Message msg = peekEarliestMessage(); - - if (DEBUG && msg != null) { - Log.v(TAG, "Next found message " + msg + " isAsynchronous: " - + msg.isAsynchronous() + " target " + msg.target); - } - - if (msg != null && !msg.isAsynchronous() && msg.target == null) { - // Stalled by a barrier. Find the next asynchronous message in the queue. - msg = mAsyncPriorityQueue.peek(); - if (DEBUG) { - Log.v(TAG, "Next message was barrier async msg: " + msg); - } - } - - if (msg != null) { - if (now < msg.when) { - // Next message is not ready. Set a timeout to wake up when it is ready. - nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); - } else { - mBlocked = false; - removeRootFromPriorityQueue(msg); - if (DEBUG) Log.v(TAG, "Returning message: " + msg); - msg.markInUse(); - if (TRACE) { - Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet()); - } - return msg; - } - } else { - // No more messages. - nextPollTimeoutMillis = -1; - } - - // Process the quit message now that all pending messages have been handled. - if (mQuitting) { - dispose(); - return null; - } - - // If first time idle, then get the number of idlers to run. - // Idle handles only run if the queue is empty or if the first message - // in the queue (possibly a barrier) is due to be handled in the future. - Message next = peekEarliestMessage(); - if (pendingIdleHandlerCount < 0 - && (next == null || now < next.when)) { - pendingIdleHandlerCount = mIdleHandlers.size(); - } - if (pendingIdleHandlerCount <= 0) { - // No idle handlers to run. Loop and wait some more. - mBlocked = true; - continue; - } - - if (mPendingIdleHandlers == null) { - mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; - } - mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); - } - - // Run the idle handlers. - // We only ever reach this code block during the first iteration. - for (int i = 0; i < pendingIdleHandlerCount; i++) { - final IdleHandler idler = mPendingIdleHandlers[i]; - mPendingIdleHandlers[i] = null; // release the reference to the handler - - boolean keep = false; - try { - keep = idler.queueIdle(); - } catch (Throwable t) { - Log.wtf(TAG, "IdleHandler threw exception", t); - } - - if (!keep) { - synchronized (this) { - mIdleHandlers.remove(idler); - } - } - } - - // Reset the idle handler count to 0 so we do not run them again. - pendingIdleHandlerCount = 0; - - // While calling an idle handler, a new message could have been delivered - // so go back and look again for a pending message without waiting. - nextPollTimeoutMillis = 0; - } - } - - void quit(boolean safe) { - if (!mQuitAllowed) { - throw new IllegalStateException("Main thread not allowed to quit."); - } - - synchronized (this) { - if (mQuitting) { - return; - } - mQuitting = true; - - if (safe) { - removeAllFutureMessagesLocked(); - } else { - removeAllMessagesLocked(); - } - - // We can assume mPtr != 0 because mQuitting was previously false. - nativeWake(mPtr); - } - } - - /** - * Posts a synchronization barrier to the Looper's message queue. - * - * Message processing occurs as usual until the message queue encounters the - * synchronization barrier that has been posted. When the barrier is encountered, - * later synchronous messages in the queue are stalled (prevented from being executed) - * until the barrier is released by calling {@link #removeSyncBarrier} and specifying - * the token that identifies the synchronization barrier. - * - * This method is used to immediately postpone execution of all subsequently posted - * synchronous messages until a condition is met that releases the barrier. - * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier - * and continue to be processed as usual. - * - * This call must be always matched by a call to {@link #removeSyncBarrier} with - * the same token to ensure that the message queue resumes normal operation. - * Otherwise the application will probably hang! - * - * @return A token that uniquely identifies the barrier. This token must be - * passed to {@link #removeSyncBarrier} to release the barrier. - * - * @hide - */ - @UnsupportedAppUsage - @TestApi - public int postSyncBarrier() { - return postSyncBarrier(SystemClock.uptimeMillis()); - } - - private int postSyncBarrier(long when) { - // Enqueue a new sync barrier token. - // We don't need to wake the queue because the purpose of a barrier is to stall it. - synchronized (this) { - final int token = mNextBarrierToken++; - final Message msg = Message.obtain(); - msg.arg1 = token; - - enqueueMessageUnchecked(msg, when); - return token; - } - } - - private class MatchBarrierToken extends MessageHeap.MessageHeapCompare { - int mBarrierToken; - - MatchBarrierToken(int token) { - super(); - mBarrierToken = token; - } - - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == null && m.arg1 == mBarrierToken) { - return true; - } - return false; - } - } - - /** - * Removes a synchronization barrier. - * - * @param token The synchronization barrier token that was returned by - * {@link #postSyncBarrier}. - * - * @throws IllegalStateException if the barrier was not found. - * - * @hide - */ - @UnsupportedAppUsage - @TestApi - public void removeSyncBarrier(int token) { - final MatchBarrierToken matchBarrierToken = new MatchBarrierToken(token); - - // Remove a sync barrier token from the queue. - // If the queue is no longer stalled by a barrier then wake it. - synchronized (this) { - boolean removed; - Message first = mPriorityQueue.peek(); - - removed = mPriorityQueue.findOrRemoveMessages(null, 0, null, null, 0, - matchBarrierToken, true); - if (removed && first != null) { - // If the loop is quitting then it is already awake. - // We can assume mPtr != 0 when mQuitting is false. - if (first.target == null && first.arg1 == token && !mQuitting) { - nativeWake(mPtr); - } - } else if (!removed) { - throw new IllegalStateException("The specified message queue synchronization " - + " barrier token has not been posted or has already been removed."); - } - } - } - - boolean enqueueMessage(Message msg, long when) { - if (msg.target == null) { - throw new IllegalArgumentException("Message must have a target."); - } - - return enqueueMessageUnchecked(msg, when); - } - - boolean enqueueMessageUnchecked(Message msg, long when) { - synchronized (this) { - if (mQuitting) { - IllegalStateException e = new IllegalStateException( - msg.target + " sending message to a Handler on a dead thread"); - Log.w(TAG, e.getMessage(), e); - msg.recycle(); - return false; - } - - if (msg.isInUse()) { - throw new IllegalStateException(msg + " This message is already in use."); - } - - msg.markInUse(); - msg.when = when; - msg.mInsertSeq = when != 0 ? mNextInsertSeq++ : mNextFrontInsertSeq--; - if (DEBUG) Log.v(TAG, "Enqueue message: " + msg); - boolean needWake; - boolean isBarrier = msg.target == null; - Message first = peekEarliestMessage(); - - if (priorityQueuesAreEmpty() || when == 0 || when < first.when) { - needWake = mBlocked && !isBarrier; - } else { - Message firstNonAsyncMessage = - first.isAsynchronous() ? mPriorityQueue.peek() : first; - - needWake = mBlocked && firstNonAsyncMessage != null - && firstNonAsyncMessage.target == null && msg.isAsynchronous(); - } - - if (msg.isAsynchronous()) { - mAsyncPriorityQueue.add(msg); - } else { - mPriorityQueue.add(msg); - } - - // We can assume mPtr != 0 because mQuitting is false. - if (needWake) { - nativeWake(mPtr); - } - } - return true; - } - - @GuardedBy("this") - boolean findOrRemoveMessages(Handler h, int what, Object object, Runnable r, long when, - MessageHeap.MessageHeapCompare compare, boolean removeMatches) { - boolean found = mPriorityQueue.findOrRemoveMessages(h, what, object, r, when, compare, - removeMatches); - boolean foundAsync = mAsyncPriorityQueue.findOrRemoveMessages(h, what, object, r, when, - compare, removeMatches); - return found || foundAsync; - } - - private static class MatchHandlerWhatAndObject extends MessageHeap.MessageHeapCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && m.what == what && (object == null || m.obj == object)) { - return true; - } - return false; - } - } - private static final MatchHandlerWhatAndObject sMatchHandlerWhatAndObject = - new MatchHandlerWhatAndObject(); - - boolean hasMessages(Handler h, int what, Object object) { - if (h == null) { - return false; - } - - synchronized (this) { - return findOrRemoveMessages(h, what, object, null, 0, sMatchHandlerWhatAndObject, - false); - } - } - - private static class MatchHandlerWhatAndObjectEquals extends MessageHeap.MessageHeapCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) { - return true; - } - return false; - } - } - private static final MatchHandlerWhatAndObjectEquals sMatchHandlerWhatAndObjectEquals = - new MatchHandlerWhatAndObjectEquals(); - boolean hasEqualMessages(Handler h, int what, Object object) { - if (h == null) { - return false; - } - - synchronized (this) { - return findOrRemoveMessages(h, what, object, null, 0, - sMatchHandlerWhatAndObjectEquals, false); - } - } - - private static class MatchHandlerRunnableAndObject extends MessageHeap.MessageHeapCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && m.callback == r && (object == null || m.obj == object)) { - return true; - } - return false; - } - } - private static final MatchHandlerRunnableAndObject sMatchHandlerRunnableAndObject = - new MatchHandlerRunnableAndObject(); - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - boolean hasMessages(Handler h, Runnable r, Object object) { - if (h == null) { - return false; - } - - synchronized (this) { - return findOrRemoveMessages(h, -1, object, r, 0, sMatchHandlerRunnableAndObject, - false); - } - } - - private static class MatchHandler extends MessageHeap.MessageHeapCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h) { - return true; - } - return false; - } - } - private static final MatchHandler sMatchHandler = new MatchHandler(); - boolean hasMessages(Handler h) { - if (h == null) { - return false; - } - - synchronized (this) { - return findOrRemoveMessages(h, -1, null, null, 0, sMatchHandler, false); - } - } - - void removeMessages(Handler h, int what, Object object) { - if (h == null) { - return; - } - - synchronized (this) { - findOrRemoveMessages(h, what, object, null, 0, sMatchHandlerWhatAndObject, true); - } - } - - void removeEqualMessages(Handler h, int what, Object object) { - if (h == null) { - return; - } - - synchronized (this) { - findOrRemoveMessages(h, what, object, null, 0, sMatchHandlerWhatAndObjectEquals, true); - } - } - - void removeMessages(Handler h, Runnable r, Object object) { - if (h == null || r == null) { - return; - } - - synchronized (this) { - findOrRemoveMessages(h, -1, object, r, 0, sMatchHandlerRunnableAndObject, true); - } - } - - private static class MatchHandlerRunnableAndObjectEquals - extends MessageHeap.MessageHeapCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) { - return true; - } - return false; - } - } - private static final MatchHandlerRunnableAndObjectEquals sMatchHandlerRunnableAndObjectEquals = - new MatchHandlerRunnableAndObjectEquals(); - void removeEqualMessages(Handler h, Runnable r, Object object) { - if (h == null || r == null) { - return; - } - - synchronized (this) { - findOrRemoveMessages(h, -1, object, r, 0, sMatchHandlerRunnableAndObjectEquals, true); - } - } - - private static class MatchHandlerAndObject extends MessageHeap.MessageHeapCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && (object == null || m.obj == object)) { - return true; - } - return false; - } - } - private static final MatchHandlerAndObject sMatchHandlerAndObject = new MatchHandlerAndObject(); - void removeCallbacksAndMessages(Handler h, Object object) { - if (h == null) { - return; - } - - synchronized (this) { - findOrRemoveMessages(h, -1, object, null, 0, sMatchHandlerAndObject, true); - } - } - - private static class MatchHandlerAndObjectEquals extends MessageHeap.MessageHeapCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && (object == null || object.equals(m.obj))) { - return true; - } - return false; - } - } - private static final MatchHandlerAndObjectEquals sMatchHandlerAndObjectEquals = - new MatchHandlerAndObjectEquals(); - void removeCallbacksAndEqualMessages(Handler h, Object object) { - if (h == null) { - return; - } - - synchronized (this) { - findOrRemoveMessages(h, -1, object, null, 0, sMatchHandlerAndObjectEquals, true); - } - } - - @GuardedBy("this") - private void removeAllMessagesLocked() { - mPriorityQueue.removeAll(); - mAsyncPriorityQueue.removeAll(); - } - - private static class MatchAllFutureMessages extends MessageHeap.MessageHeapCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.when > when) { - return true; - } - return false; - } - } - private static final MatchAllFutureMessages sMatchAllFutureMessages = - new MatchAllFutureMessages(); - @GuardedBy("this") - private void removeAllFutureMessagesLocked() { - findOrRemoveMessages(null, -1, null, null, SystemClock.uptimeMillis(), - sMatchAllFutureMessages, true); - } - - @NeverCompile - int dumpPriorityQueue(Printer pw, String prefix, Handler h, MessageHeap priorityQueue) { - int n = 0; - long now = SystemClock.uptimeMillis(); - for (int i = 0; i < priorityQueue.numElements(); i++) { - Message m = priorityQueue.getMessageAt(i); - if (h == null && h == m.target) { - pw.println(prefix + "Message " + n + ": " + m.toString(now)); - n++; - } - } - return n; - } - - @NeverCompile - void dumpPriorityQueue(ProtoOutputStream proto, MessageHeap priorityQueue) { - for (int i = 0; i < priorityQueue.numElements(); i++) { - Message m = priorityQueue.getMessageAt(i); - m.dumpDebug(proto, MessageQueueProto.MESSAGES); - } - } - - @NeverCompile - void dump(Printer pw, String prefix, Handler h) { - synchronized (this) { - pw.println(prefix + "(MessageQueue is using Locked implementation)"); - long now = SystemClock.uptimeMillis(); - int n = dumpPriorityQueue(pw, prefix, h, mPriorityQueue); - n += dumpPriorityQueue(pw, prefix, h, mAsyncPriorityQueue); - pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked() - + ", quitting=" + mQuitting + ")"); - } - } - - @NeverCompile - void dumpDebug(ProtoOutputStream proto, long fieldId) { - final long messageQueueToken = proto.start(fieldId); - synchronized (this) { - dumpPriorityQueue(proto, mPriorityQueue); - dumpPriorityQueue(proto, mAsyncPriorityQueue); - proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked()); - proto.write(MessageQueueProto.IS_QUITTING, mQuitting); - } - proto.end(messageQueueToken); - } - - /** - * Callback interface for discovering when a thread is going to block - * waiting for more messages. - */ - public static interface IdleHandler { - /** - * Called when the message queue has run out of messages and will now - * wait for more. Return true to keep your idle handler active, false - * to have it removed. This may be called if there are still messages - * pending in the queue, but they are all scheduled to be dispatched - * after the current time. - */ - boolean queueIdle(); - } - - /** - * A listener which is invoked when file descriptor related events occur. - */ - public interface OnFileDescriptorEventListener { - /** - * File descriptor event: Indicates that the file descriptor is ready for input - * operations, such as reading. - * <p> - * The listener should read all available data from the file descriptor - * then return <code>true</code> to keep the listener active or <code>false</code> - * to remove the listener. - * </p><p> - * In the case of a socket, this event may be generated to indicate - * that there is at least one incoming connection that the listener - * should accept. - * </p><p> - * This event will only be generated if the {@link #EVENT_INPUT} event mask was - * specified when the listener was added. - * </p> - */ - public static final int EVENT_INPUT = 1 << 0; - - /** - * File descriptor event: Indicates that the file descriptor is ready for output - * operations, such as writing. - * <p> - * The listener should write as much data as it needs. If it could not - * write everything at once, then it should return <code>true</code> to - * keep the listener active. Otherwise, it should return <code>false</code> - * to remove the listener then re-register it later when it needs to write - * something else. - * </p><p> - * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was - * specified when the listener was added. - * </p> - */ - public static final int EVENT_OUTPUT = 1 << 1; - - /** - * File descriptor event: Indicates that the file descriptor encountered a - * fatal error. - * <p> - * File descriptor errors can occur for various reasons. One common error - * is when the remote peer of a socket or pipe closes its end of the connection. - * </p><p> - * This event may be generated at any time regardless of whether the - * {@link #EVENT_ERROR} event mask was specified when the listener was added. - * </p> - */ - public static final int EVENT_ERROR = 1 << 2; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, prefix = { "EVENT_" }, value = { - EVENT_INPUT, - EVENT_OUTPUT, - EVENT_ERROR - }) - public @interface Events {} - - /** - * Called when a file descriptor receives events. - * - * @param fd The file descriptor. - * @param events The set of events that occurred: a combination of the - * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks. - * @return The new set of events to watch, or 0 to unregister the listener. - * - * @see #EVENT_INPUT - * @see #EVENT_OUTPUT - * @see #EVENT_ERROR - */ - @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events); - } - - private static final class FileDescriptorRecord { - public final FileDescriptor mDescriptor; - public int mEvents; - public OnFileDescriptorEventListener mListener; - public int mSeq; - - public FileDescriptorRecord(FileDescriptor descriptor, - int events, OnFileDescriptorEventListener listener) { - mDescriptor = descriptor; - mEvents = events; - mListener = listener; - } - } -} diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index d16e4473d55f..1329b90538bb 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -200,7 +200,11 @@ public final class Looper { } PerfettoTrace.begin(PerfettoTrace.MQ_CATEGORY, "message_queue_receive") - .addArg("sending_thread", msg.mSendingThreadName) + .beginProto() + .beginNested(2004 /* message_queue */) + .addField(1 /* sending_thread_name */, msg.mSendingThreadName) + .endNested() + .endProto() .addTerminatingFlow(msg.mEventId.get()) .emit(); diff --git a/core/java/android/os/PerfettoTrackEventExtra.java b/core/java/android/os/PerfettoTrackEventExtra.java index adb98aa25f8f..68442293c3a3 100644 --- a/core/java/android/os/PerfettoTrackEventExtra.java +++ b/core/java/android/os/PerfettoTrackEventExtra.java @@ -23,6 +23,8 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Supplier; @@ -50,6 +52,7 @@ public final class PerfettoTrackEventExtra { private static final Supplier<FieldString> sFieldStringSupplier = FieldString::new; private static final Supplier<FieldNested> sFieldNestedSupplier = FieldNested::new; + private final List<PerfettoPointer> mPendingPointers = new ArrayList<>(); private CounterInt64 mCounterInt64; private CounterDouble mCounterDouble; private Proto mProto; @@ -592,7 +595,7 @@ public final class PerfettoTrackEventExtra { checkContainer(); FieldInt64 field = mFieldInt64Cache.get(sFieldInt64Supplier); field.setValue(id, val); - mCurrentContainer.addField(field); + mExtra.addPerfettoPointer(mCurrentContainer, field); return this; } @@ -601,7 +604,7 @@ public final class PerfettoTrackEventExtra { checkContainer(); FieldDouble field = mFieldDoubleCache.get(sFieldDoubleSupplier); field.setValue(id, val); - mCurrentContainer.addField(field); + mExtra.addPerfettoPointer(mCurrentContainer, field); return this; } @@ -610,7 +613,7 @@ public final class PerfettoTrackEventExtra { checkContainer(); FieldString field = mFieldStringCache.get(sFieldStringSupplier); field.setValue(id, val); - mCurrentContainer.addField(field); + mExtra.addPerfettoPointer(mCurrentContainer, field); return this; } @@ -635,7 +638,7 @@ public final class PerfettoTrackEventExtra { checkContainer(); FieldNested field = mFieldNestedCache.get(sFieldNestedSupplier); field.setId(id); - mCurrentContainer.addField(field); + mExtra.addPerfettoPointer(mCurrentContainer, field); return mBuilderCache.get(sBuilderSupplier).initInternal(this, field); } @@ -735,6 +738,15 @@ public final class PerfettoTrackEventExtra { */ public void addPerfettoPointer(PerfettoPointer extra) { native_add_arg(mPtr, extra.getPtr()); + mPendingPointers.add(extra); + } + + /** + * Adds a pointer representing a track event parameter to the {@code container}. + */ + public void addPerfettoPointer(FieldContainer container, PerfettoPointer extra) { + container.addField(extra); + mPendingPointers.add(extra); } /** @@ -742,6 +754,7 @@ public final class PerfettoTrackEventExtra { */ public void reset() { native_clear_args(mPtr); + mPendingPointers.clear(); } private CounterInt64 getCounterInt64() { diff --git a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java deleted file mode 100644 index 435c34f832c6..000000000000 --- a/core/java/android/os/SemiConcurrentMessageQueue/MessageQueue.java +++ /dev/null @@ -1,1600 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.TestApi; -import android.ravenwood.annotation.RavenwoodKeepWholeClass; -import android.ravenwood.annotation.RavenwoodRedirect; -import android.ravenwood.annotation.RavenwoodRedirectionClass; -import android.util.Log; -import android.util.Printer; -import android.util.SparseArray; -import android.util.proto.ProtoOutputStream; - -import com.android.internal.annotations.GuardedBy; - -import dalvik.annotation.optimization.NeverCompile; - -import java.io.FileDescriptor; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.PriorityQueue; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Low-level class holding the list of messages to be dispatched by a - * {@link Looper}. Messages are not added directly to a MessageQueue, - * but rather through {@link Handler} objects associated with the Looper. - * - * <p>You can retrieve the MessageQueue for the current thread with - * {@link Looper#myQueue() Looper.myQueue()}. - */ -@RavenwoodKeepWholeClass -@RavenwoodRedirectionClass("MessageQueue_ravenwood") -public final class MessageQueue { - private static final String TAG = "SemiConcurrentMessageQueue"; - private static final boolean DEBUG = false; - private static final boolean TRACE = false; - - // True if the message queue can be quit. - private final boolean mQuitAllowed; - - @SuppressWarnings("unused") - private long mPtr; // used by native code - - @IntDef(value = { - STACK_NODE_MESSAGE, - STACK_NODE_ACTIVE, - STACK_NODE_PARKED, - STACK_NODE_TIMEDPARK}) - @Retention(RetentionPolicy.SOURCE) - private @interface StackNodeType {} - - /* - * Stack node types. STACK_NODE_MESSAGE indicates a node containing a message. - * The other types indicate what state our Looper thread is in. The bottom of - * the stack is always a single state node. Message nodes are added on top. - */ - private static final int STACK_NODE_MESSAGE = 0; - /* - * Active state indicates that next() is processing messages - */ - private static final int STACK_NODE_ACTIVE = 1; - /* - * Parked state indicates that the Looper thread is sleeping indefinitely (nothing to deliver) - */ - private static final int STACK_NODE_PARKED = 2; - /* - * Timed Park state indicates that the Looper thread is sleeping, waiting for a message - * deadline - */ - private static final int STACK_NODE_TIMEDPARK = 3; - - /* Describes a node in the Treiber stack */ - static class StackNode { - @StackNodeType - private final int mType; - - StackNode(@StackNodeType int type) { - mType = type; - } - - @StackNodeType - final int getNodeType() { - return mType; - } - - final boolean isMessageNode() { - return mType == STACK_NODE_MESSAGE; - } - } - - static final class MessageNode extends StackNode implements Comparable<MessageNode> { - private final Message mMessage; - volatile StackNode mNext; - StateNode mBottomOfStack; - boolean mWokeUp; - boolean mRemovedFromStack = false; - final long mInsertSeq; - - MessageNode(@NonNull Message message, long insertSeq) { - super(STACK_NODE_MESSAGE); - mMessage = message; - mInsertSeq = insertSeq; - } - - long getWhen() { - return mMessage.when; - } - - boolean isRemovedFromStack() { - return mRemovedFromStack; - } - - boolean removeFromStack() { - if (!mRemovedFromStack) { - mRemovedFromStack = true; - return true; - } - return false; - } - - boolean isAsync() { - return mMessage.isAsynchronous(); - } - - boolean isBarrier() { - return mMessage.target == null; - } - - @Override - public int compareTo(@NonNull MessageNode messageNode) { - Message other = messageNode.mMessage; - - int compared = Long.compare(mMessage.when, other.when); - if (compared == 0) { - compared = Long.compare(mInsertSeq, messageNode.mInsertSeq); - } - return compared; - } - } - - static class StateNode extends StackNode { - StateNode(int type) { - super(type); - } - } - - static final class TimedParkStateNode extends StateNode { - long mWhenToWake; - - TimedParkStateNode() { - super(STACK_NODE_TIMEDPARK); - } - } - - private static final StateNode sStackStateActive = new StateNode(STACK_NODE_ACTIVE); - private static final StateNode sStackStateParked = new StateNode(STACK_NODE_PARKED); - private final TimedParkStateNode mStackStateTimedPark = new TimedParkStateNode(); - - /* This is the top of our treiber stack. */ - private static final VarHandle sState; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - sState = l.findVarHandle(MessageQueue.class, "mStateValue", - MessageQueue.StackNode.class); - } catch (Exception e) { - Log.wtf(TAG, "VarHandle lookup failed with exception: " + e); - throw new ExceptionInInitializerError(e); - } - } - - private volatile StackNode mStateValue = sStackStateParked; - @GuardedBy("mPriorityQueue") - private final PriorityQueue<MessageNode> mPriorityQueue = - new PriorityQueue<MessageNode>(); - @GuardedBy("mPriorityQueue") - private final PriorityQueue<MessageNode> mAsyncPriorityQueue = - new PriorityQueue<MessageNode>(); - - /* - * This helps us ensure that messages with the same timestamp are inserted in FIFO order. - * Increments on each insert, starting at 0. MessageNode.compareTo() will compare sequences - * when delivery timestamps are identical. - */ - private static final VarHandle sNextInsertSeq; - private volatile long mNextInsertSeqValue = 0; - /* - * The exception to the FIFO order rule is sendMessageAtFrontOfQueue(). - * Those messages must be in LIFO order. - * Decrements on each front of queue insert. - */ - private static final VarHandle sNextFrontInsertSeq; - private volatile long mNextFrontInsertSeqValue = -1; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - sNextInsertSeq = l.findVarHandle(MessageQueue.class, "mNextInsertSeqValue", - long.class); - sNextFrontInsertSeq = l.findVarHandle(MessageQueue.class, "mNextFrontInsertSeqValue", - long.class); - } catch (Exception e) { - Log.wtf(TAG, "VarHandle lookup failed with exception: " + e); - throw new ExceptionInInitializerError(e); - } - - } - - /* - * Tracks the number of queued and cancelled messages in our stack. - * - * On item cancellation, determine whether to wake next() to flush tombstoned messages. - * We track queued and cancelled counts as two ints packed into a single long. - */ - private static final class MessageCounts { - private static VarHandle sCounts; - private volatile long mCountsValue = 0; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - sCounts = l.findVarHandle(MessageQueue.MessageCounts.class, "mCountsValue", - long.class); - } catch (Exception e) { - Log.wtf(TAG, "VarHandle lookup failed with exception: " + e); - throw new ExceptionInInitializerError(e); - } - } - /* We use a special value to indicate when next() has been woken for flush. */ - private static final long AWAKE = Long.MAX_VALUE; - /* - * Minimum number of messages in the stack which we need before we consider flushing - * tombstoned items. - */ - private static final int MESSAGE_FLUSH_THRESHOLD = 10; - - private static int numQueued(long val) { - return (int) (val >>> Integer.SIZE); - } - - private static int numCancelled(long val) { - return (int) val; - } - - private static long combineCounts(int queued, int cancelled) { - return ((long) queued << Integer.SIZE) | (long) cancelled; - } - - public void incrementQueued() { - while (true) { - long oldVal = mCountsValue; - int queued = numQueued(oldVal); - int cancelled = numCancelled(oldVal); - /* Use Math.max() to avoid overflow of queued count */ - long newVal = combineCounts(Math.max(queued + 1, queued), cancelled); - - /* Don't overwrite 'AWAKE' state */ - if (oldVal == AWAKE || sCounts.compareAndSet(this, oldVal, newVal)) { - break; - } - } - } - - public boolean incrementCancelled() { - while (true) { - long oldVal = mCountsValue; - if (oldVal == AWAKE) { - return false; - } - int queued = numQueued(oldVal); - int cancelled = numCancelled(oldVal); - boolean needsPurge = queued > MESSAGE_FLUSH_THRESHOLD - && (queued >> 1) < cancelled; - long newVal; - if (needsPurge) { - newVal = AWAKE; - } else { - newVal = combineCounts(queued, - Math.max(cancelled + 1, cancelled)); - } - - if (sCounts.compareAndSet(this, oldVal, newVal)) { - return needsPurge; - } - } - } - - public void clearCounts() { - mCountsValue = 0; - } - } - - private final MessageCounts mMessageCounts = new MessageCounts(); - - private final Object mIdleHandlersLock = new Object(); - @GuardedBy("mIdleHandlersLock") - private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); - private IdleHandler[] mPendingIdleHandlers; - - private final Object mFileDescriptorRecordsLock = new Object(); - @GuardedBy("mFileDescriptorRecordsLock") - private SparseArray<FileDescriptorRecord> mFileDescriptorRecords; - - private static final VarHandle sQuitting; - private boolean mQuittingValue = false; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - sQuitting = l.findVarHandle(MessageQueue.class, "mQuittingValue", boolean.class); - } catch (Exception e) { - Log.wtf(TAG, "VarHandle lookup failed with exception: " + e); - throw new ExceptionInInitializerError(e); - } - } - - // The next barrier token. - // Barriers are indicated by messages with a null target whose arg1 field carries the token. - private final AtomicInteger mNextBarrierToken = new AtomicInteger(1); - - @RavenwoodRedirect - private static native long nativeInit(); - @RavenwoodRedirect - private static native void nativeDestroy(long ptr); - @RavenwoodRedirect - private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/ - @RavenwoodRedirect - private static native void nativeWake(long ptr); - @RavenwoodRedirect - private static native boolean nativeIsPolling(long ptr); - @RavenwoodRedirect - private static native void nativeSetFileDescriptorEvents(long ptr, int fd, int events); - - MessageQueue(boolean quitAllowed) { - mQuitAllowed = quitAllowed; - mPtr = nativeInit(); - } - - @Override - protected void finalize() throws Throwable { - try { - dispose(); - } finally { - super.finalize(); - } - } - - // Disposes of the underlying message queue. - // Must only be called on the looper thread or the finalizer. - private void dispose() { - if (mPtr != 0) { - nativeDestroy(mPtr); - mPtr = 0; - } - } - - /** - * Returns true if the looper has no pending messages which are due to be processed. - * - * <p>This method is safe to call from any thread. - * - * @return True if the looper is idle. - */ - public boolean isIdle() { - MessageNode msgNode = null; - MessageNode asyncMsgNode = null; - - synchronized (mPriorityQueue) { - msgNode = mPriorityQueue.peek(); - asyncMsgNode = mAsyncPriorityQueue.peek(); - - final long now = SystemClock.uptimeMillis(); - if ((msgNode != null && msgNode.getWhen() <= now) - || (asyncMsgNode != null && asyncMsgNode.getWhen() <= now)) { - return false; - } - } - - return true; - } - - /** - * Add a new {@link IdleHandler} to this message queue. This may be - * removed automatically for you by returning false from - * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is - * invoked, or explicitly removing it with {@link #removeIdleHandler}. - * - * <p>This method is safe to call from any thread. - * - * @param handler The IdleHandler to be added. - */ - public void addIdleHandler(@NonNull IdleHandler handler) { - if (handler == null) { - throw new NullPointerException("Can't add a null IdleHandler"); - } - synchronized (mIdleHandlersLock) { - mIdleHandlers.add(handler); - } - } - - /** - * Remove an {@link IdleHandler} from the queue that was previously added - * with {@link #addIdleHandler}. If the given object is not currently - * in the idle list, nothing is done. - * - * <p>This method is safe to call from any thread. - * - * @param handler The IdleHandler to be removed. - */ - public void removeIdleHandler(@NonNull IdleHandler handler) { - synchronized (mIdleHandlersLock) { - mIdleHandlers.remove(handler); - } - } - - /** - * Returns whether this looper's thread is currently polling for more work to do. - * This is a good signal that the loop is still alive rather than being stuck - * handling a callback. Note that this method is intrinsically racy, since the - * state of the loop can change before you get the result back. - * - * <p>This method is safe to call from any thread. - * - * @return True if the looper is currently polling for events. - * @hide - */ - public boolean isPolling() { - // If the loop is quitting then it must not be idling. - // We can assume mPtr != 0 when sQuitting is false. - return !((boolean) sQuitting.getVolatile(this)) && nativeIsPolling(mPtr); - } - - /* Helper to choose the correct queue to insert into. */ - @GuardedBy("mPriorityQueue") - private void insertIntoPriorityQueue(MessageNode msgNode) { - if (msgNode.isAsync()) { - mAsyncPriorityQueue.offer(msgNode); - } else { - mPriorityQueue.offer(msgNode); - } - } - - @GuardedBy("mPriorityQueue") - private boolean removeFromPriorityQueue(MessageNode msgNode) { - if (msgNode.isAsync()) { - return mAsyncPriorityQueue.remove(msgNode); - } else { - return mPriorityQueue.remove(msgNode); - } - } - - private MessageNode pickEarliestNode(MessageNode nodeA, MessageNode nodeB) { - if (nodeA != null && nodeB != null) { - if (nodeA.compareTo(nodeB) < 0) { - return nodeA; - } - return nodeB; - } - - return nodeA != null ? nodeA : nodeB; - } - - /* Move any non-cancelled messages into the priority queue */ - private void drainStack(StackNode oldTop) { - while (oldTop.isMessageNode()) { - MessageNode oldTopMessageNode = (MessageNode) oldTop; - if (oldTopMessageNode.removeFromStack()) { - insertIntoPriorityQueue(oldTopMessageNode); - } - MessageNode inserted = oldTopMessageNode; - oldTop = oldTopMessageNode.mNext; - } - } - - /* Set the stack state to Active, return a list of nodes to walk. */ - private StackNode swapAndSetStackStateActive() { - while (true) { - /* Set stack state to Active, get node list to walk later */ - StackNode current = (StackNode) sState.getVolatile(this); - if (current == sStackStateActive - || sState.compareAndSet(this, current, sStackStateActive)) { - return current; - } - } - } - - /* This is only read/written from the Looper thread */ - private int mNextPollTimeoutMillis; - private static final AtomicLong mMessagesDelivered = new AtomicLong(); - - private Message nextMessage() { - int i = 0; - - while (true) { - if (DEBUG) { - Log.d(TAG, "nextMessage loop #" + i); - i++; - } - - /* This protects us from racing with remove. Enqueue can still add items. */ - synchronized (mPriorityQueue) { - - /* - * Set our state to active, drain any items from the stack into our priority queues - */ - StackNode oldTop; - oldTop = swapAndSetStackStateActive(); - drainStack(oldTop); - - /* - * The objective of this next block of code is to: - * - find a message to return (if any is ready) - * - find a next message we would like to return, after scheduling. - * - we make our scheduling decision based on this next message (if it exists). - * - * We have two queues to juggle and the presence of barriers throws an additional - * wrench into our plans. - */ - - /* Get the first node from each queue */ - MessageNode msgNode = mPriorityQueue.peek(); - MessageNode asyncMsgNode = mAsyncPriorityQueue.peek(); - - if (DEBUG) { - if (msgNode != null) { - Message msg = msgNode.mMessage; - Log.d(TAG, "Next found node what: " + msg.what + " when: " + msg.when - + " seq: " + msgNode.mInsertSeq + "barrier: " - + msgNode.isBarrier() + " now: " - + SystemClock.uptimeMillis()); - } - if (asyncMsgNode != null) { - Message msg = asyncMsgNode.mMessage; - Log.d(TAG, "Next found async node what: " + msg.what + " when: " + msg.when - + " seq: " + asyncMsgNode.mInsertSeq + "barrier: " - + asyncMsgNode.isBarrier() + " now: " - + SystemClock.uptimeMillis()); - } - } - - /* - * the node which we will return, null if none are ready - */ - MessageNode found = null; - /* - * The node from which we will determine our next wakeup time. - * Null indicates there is no next message ready. If we found a node, - * we can leave this null as Looper will call us again after delivering - * the message. - */ - MessageNode next = null; - - long now = SystemClock.uptimeMillis(); - /* - * If we have a barrier we should return the async node if it exists and is - * ready - */ - if (msgNode != null && msgNode.isBarrier()) { - if (asyncMsgNode != null && now >= asyncMsgNode.getWhen()) { - found = asyncMsgNode; - removeFromPriorityQueue(found); - } else { - next = asyncMsgNode; - } - } else { /* No barrier. */ - MessageNode earliest; - /* - * If we have two messages, pick the earliest option from either queue. - * Otherwise grab whichever node is non-null. If both are null we'll fall - * through. - */ - earliest = pickEarliestNode(msgNode, asyncMsgNode); - - if (earliest != null) { - if (now >= earliest.getWhen()) { - found = earliest; - removeFromPriorityQueue(found); - } else { - next = earliest; - } - } - } - - if (DEBUG) { - if (found != null) { - Message msg = found.mMessage; - Log.d(TAG, "Will deliver node what: " + msg.what + " when: " + msg.when - + " seq: " + found.mInsertSeq + " barrier: " - + found.isBarrier() + " async: " + found.isAsync() - + " now: " + SystemClock.uptimeMillis()); - } else { - Log.d(TAG, "No node to deliver"); - } - if (next != null) { - Message msg = next.mMessage; - Log.d(TAG, "Next node what: " + msg.what + " when: " + msg.when + " seq: " - + next.mInsertSeq + " barrier: " + next.isBarrier() - + " async: " + next.isAsync() - + " now: " + SystemClock.uptimeMillis()); - } else { - Log.d(TAG, "No next node"); - } - } - - /* - * If we have a found message, we will get called again so there's no need to set - * state. - * In that case we can leave our state as ACTIVE. - * - * Otherwise we should determine how to park the thread. - */ - StateNode nextOp = sStackStateActive; - if (found == null) { - if (next == null) { - /* No message to deliver, sleep indefinitely */ - mNextPollTimeoutMillis = -1; - nextOp = sStackStateParked; - if (DEBUG) { - Log.d(TAG, "nextMessage next state is StackStateParked"); - } - } else { - /* Message not ready, or we found one to deliver already, set a timeout */ - long nextMessageWhen = next.getWhen(); - if (nextMessageWhen > now) { - mNextPollTimeoutMillis = (int) Math.min(nextMessageWhen - now, - Integer.MAX_VALUE); - } else { - mNextPollTimeoutMillis = 0; - } - - mStackStateTimedPark.mWhenToWake = now + mNextPollTimeoutMillis; - nextOp = mStackStateTimedPark; - if (DEBUG) { - Log.d(TAG, "nextMessage next state is StackStateTimedParked " - + " next timeout ms " + mNextPollTimeoutMillis - + " mWhenToWake: " + mStackStateTimedPark.mWhenToWake - + " now " + now); - } - } - } - - /* - * Try to swap our state from Active back to Park or TimedPark. If we raced with - * enqueue, loop back around to pick up any new items. - */ - if (sState.compareAndSet(this, sStackStateActive, nextOp)) { - mMessageCounts.clearCounts(); - if (found != null) { - if (TRACE) { - Trace.setCounter("MQ.Delivered", mMessagesDelivered.incrementAndGet()); - } - return found.mMessage; - } - return null; - } - if (found != null) { - /* - * Add this node back - we will be adding new nodes into our priority queue, and - * recalculating what to return. - */ - insertIntoPriorityQueue(found); - } - } - } - } - - Message next() { - final long ptr = mPtr; - if (ptr == 0) { - return null; - } - - mNextPollTimeoutMillis = 0; - int pendingIdleHandlerCount = -1; // -1 only during first iteration - while (true) { - if (mNextPollTimeoutMillis != 0) { - Binder.flushPendingCommands(); - } - - nativePollOnce(ptr, mNextPollTimeoutMillis); - - Message msg = nextMessage(); - if (msg != null) { - msg.markInUse(); - return msg; - } - - if ((boolean) sQuitting.getVolatile(this)) { - return null; - } - - synchronized (mIdleHandlersLock) { - // If first time idle, then get the number of idlers to run. - // Idle handles only run if the queue is empty or if the first message - // in the queue (possibly a barrier) is due to be handled in the future. - if (pendingIdleHandlerCount < 0 - && isIdle()) { - pendingIdleHandlerCount = mIdleHandlers.size(); - } - if (pendingIdleHandlerCount <= 0) { - // No idle handlers to run. Loop and wait some more. - continue; - } - - if (mPendingIdleHandlers == null) { - mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)]; - } - mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers); - } - - // Run the idle handlers. - // We only ever reach this code block during the first iteration. - for (int i = 0; i < pendingIdleHandlerCount; i++) { - final IdleHandler idler = mPendingIdleHandlers[i]; - mPendingIdleHandlers[i] = null; // release the reference to the handler - - boolean keep = false; - try { - keep = idler.queueIdle(); - } catch (Throwable t) { - Log.wtf(TAG, "IdleHandler threw exception", t); - } - - if (!keep) { - synchronized (mIdleHandlersLock) { - mIdleHandlers.remove(idler); - } - } - } - - // Reset the idle handler count to 0 so we do not run them again. - pendingIdleHandlerCount = 0; - - // While calling an idle handler, a new message could have been delivered - // so go back and look again for a pending message without waiting. - mNextPollTimeoutMillis = 0; - } - } - - void quit(boolean safe) { - if (!mQuitAllowed) { - throw new IllegalStateException("Main thread not allowed to quit."); - } - synchronized (mIdleHandlersLock) { - if (sQuitting.compareAndSet(this, false, true)) { - if (safe) { - removeAllFutureMessages(); - } else { - removeAllMessages(); - } - - // We can assume mPtr != 0 because sQuitting was previously false. - nativeWake(mPtr); - } - } - } - - boolean enqueueMessage(@NonNull Message msg, long when) { - if (msg.target == null) { - throw new IllegalArgumentException("Message must have a target."); - } - - if (msg.isInUse()) { - throw new IllegalStateException(msg + " This message is already in use."); - } - - return enqueueMessageUnchecked(msg, when); - } - - private boolean enqueueMessageUnchecked(@NonNull Message msg, long when) { - if ((boolean) sQuitting.getVolatile(this)) { - IllegalStateException e = new IllegalStateException( - msg.target + " sending message to a Handler on a dead thread"); - Log.w(TAG, e.getMessage(), e); - msg.recycleUnchecked(); - return false; - } - - long seq = when != 0 ? ((long)sNextInsertSeq.getAndAdd(this, 1L) + 1L) - : ((long)sNextFrontInsertSeq.getAndAdd(this, -1L) - 1L); - /* TODO: Add a MessageNode member to Message so we can avoid this allocation */ - MessageNode node = new MessageNode(msg, seq); - msg.when = when; - msg.markInUse(); - - if (DEBUG) { - Log.d(TAG, "Insert message what: " + msg.what + " when: " + msg.when + " seq: " - + node.mInsertSeq + " barrier: " + node.isBarrier() + " async: " - + node.isAsync() + " now: " + SystemClock.uptimeMillis()); - } - - while (true) { - StackNode old = (StackNode) sState.getVolatile(this); - boolean wakeNeeded; - boolean inactive; - - node.mNext = old; - switch (old.getNodeType()) { - case STACK_NODE_ACTIVE: - /* - * The worker thread is currently active and will process any elements added to - * the stack before parking again. - */ - node.mBottomOfStack = (StateNode) old; - inactive = false; - node.mWokeUp = true; - wakeNeeded = false; - break; - - case STACK_NODE_PARKED: - node.mBottomOfStack = (StateNode) old; - inactive = true; - node.mWokeUp = true; - wakeNeeded = true; - break; - - case STACK_NODE_TIMEDPARK: - node.mBottomOfStack = (StateNode) old; - inactive = true; - wakeNeeded = mStackStateTimedPark.mWhenToWake >= node.getWhen(); - node.mWokeUp = wakeNeeded; - break; - - default: - MessageNode oldMessage = (MessageNode) old; - - node.mBottomOfStack = oldMessage.mBottomOfStack; - int bottomType = node.mBottomOfStack.getNodeType(); - inactive = bottomType >= STACK_NODE_PARKED; - wakeNeeded = (bottomType == STACK_NODE_TIMEDPARK - && mStackStateTimedPark.mWhenToWake >= node.getWhen() - && !oldMessage.mWokeUp); - node.mWokeUp = oldMessage.mWokeUp || wakeNeeded; - break; - } - if (sState.compareAndSet(this, old, node)) { - if (inactive) { - if (wakeNeeded) { - nativeWake(mPtr); - } else { - mMessageCounts.incrementQueued(); - } - } - return true; - } - } - } - - /** - * Posts a synchronization barrier to the Looper's message queue. - * - * Message processing occurs as usual until the message queue encounters the - * synchronization barrier that has been posted. When the barrier is encountered, - * later synchronous messages in the queue are stalled (prevented from being executed) - * until the barrier is released by calling {@link #removeSyncBarrier} and specifying - * the token that identifies the synchronization barrier. - * - * This method is used to immediately postpone execution of all subsequently posted - * synchronous messages until a condition is met that releases the barrier. - * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier - * and continue to be processed as usual. - * - * This call must be always matched by a call to {@link #removeSyncBarrier} with - * the same token to ensure that the message queue resumes normal operation. - * Otherwise the application will probably hang! - * - * @return A token that uniquely identifies the barrier. This token must be - * passed to {@link #removeSyncBarrier} to release the barrier. - * - * @hide - */ - @TestApi - public int postSyncBarrier() { - return postSyncBarrier(SystemClock.uptimeMillis()); - } - - private int postSyncBarrier(long when) { - final int token = mNextBarrierToken.getAndIncrement(); - final Message msg = Message.obtain(); - - msg.markInUse(); - msg.arg1 = token; - - if (!enqueueMessageUnchecked(msg, when)) { - Log.wtf(TAG, "Unexpected error while adding sync barrier!"); - return -1; - } - - return token; - } - - private class MatchBarrierToken extends MessageCompare { - int mBarrierToken; - - MatchBarrierToken(int token) { - super(); - mBarrierToken = token; - } - - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == null && m.arg1 == mBarrierToken) { - return true; - } - return false; - } - } - - /** - * Removes a synchronization barrier. - * - * @param token The synchronization barrier token that was returned by - * {@link #postSyncBarrier}. - * - * @throws IllegalStateException if the barrier was not found. - * - * @hide - */ - @TestApi - public void removeSyncBarrier(int token) { - boolean removed; - MessageNode first; - final MatchBarrierToken matchBarrierToken = new MatchBarrierToken(token); - - synchronized (mPriorityQueue) { - try { - /* Retain the first element to see if we are currently stuck on a barrier. */ - first = mPriorityQueue.peek(); - } catch (NoSuchElementException e) { - /* The queue is empty */ - first = null; - } - - removed = findOrRemoveMessages(null, 0, null, null, 0, matchBarrierToken, true); - if (removed && first != null) { - Message m = first.mMessage; - if (m.target == null && m.arg1 == token) { - /* Wake up next() in case it was sleeping on this barrier. */ - nativeWake(mPtr); - } - } else if (!removed) { - throw new IllegalStateException("The specified message queue synchronization " - + " barrier token has not been posted or has already been removed."); - } - } - } - - private StateNode getStateNode(StackNode node) { - if (node.isMessageNode()) { - return ((MessageNode) node).mBottomOfStack; - } - return (StateNode) node; - } - - /* - * This class is used to find matches for hasMessages() and removeMessages() - */ - private abstract static class MessageCompare { - public abstract boolean compareMessage(Message m, Handler h, int what, Object object, - Runnable r, long when); - } - @GuardedBy("mPriorityQueue") - private boolean stackHasMessages(Handler h, int what, Object object, Runnable r, long when, - MessageCompare compare, boolean removeMatches) { - boolean found = false; - StackNode top = (StackNode) sState.getVolatile(this); - StateNode bottom = getStateNode(top); - - /* No messages to search. */ - if (!top.isMessageNode()) { - return false; - } - - /* - * We have messages that we may tombstone. Walk the stack until we hit the bottom. - * next() will remove them on it's next pass. - */ - if (!(top instanceof MessageNode)) { - Log.wtf(TAG, "Unknown node type found in Trieber stack"); - } - MessageNode p = (MessageNode) top; - - while (true) { - if (compare.compareMessage(p.mMessage, h, what, object, r, when)) { - found = true; - if (DEBUG) { - Log.w(TAG, "stackHasMessages node matches"); - } - if (removeMatches) { - if (p.removeFromStack()) { - p.mMessage.recycleUnchecked(); - if (mMessageCounts.incrementCancelled()) { - nativeWake(mPtr); - } - } - } else { - return true; - } - } - - StackNode n = p.mNext; - if (!n.isMessageNode()) { - /* We reached the end of the stack */ - return found; - } - p = (MessageNode) n; - } - } - - @GuardedBy("mPriorityQueue") - private boolean priorityQueueHasMessage(PriorityQueue queue, Handler h, - int what, Object object, Runnable r, long when, MessageCompare compare, - boolean removeMatches) { - Iterator<MessageNode> iterator = queue.iterator(); - boolean found = false; - - while (iterator.hasNext()) { - MessageNode msg = iterator.next(); - - if (compare.compareMessage(msg.mMessage, h, what, object, r, when)) { - if (removeMatches) { - found = true; - iterator.remove(); - msg.mMessage.recycleUnchecked(); - } else { - return true; - } - } - } - return found; - } - - private boolean findOrRemoveMessages(Handler h, int what, Object object, Runnable r, long when, - MessageCompare compare, boolean removeMatches) { - boolean foundInStack, foundInQueue; - - synchronized (mPriorityQueue) { - foundInStack = stackHasMessages(h, what, object, r, when, compare, removeMatches); - foundInQueue = priorityQueueHasMessage(mPriorityQueue, h, what, object, r, when, - compare, removeMatches); - foundInQueue |= priorityQueueHasMessage(mAsyncPriorityQueue, h, what, object, r, when, - compare, removeMatches); - - return foundInStack || foundInQueue; - } - } - - private static class MatchHandlerWhatAndObject extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && m.what == what && (object == null || m.obj == object)) { - return true; - } - return false; - } - } - private final MatchHandlerWhatAndObject mMatchHandlerWhatAndObject = - new MatchHandlerWhatAndObject(); - boolean hasMessages(Handler h, int what, Object object) { - if (h == null) { - return false; - } - - return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, false); - } - - private static class MatchHandlerWhatAndObjectEquals extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && m.what == what && (object == null || object.equals(m.obj))) { - return true; - } - return false; - } - } - private final MatchHandlerWhatAndObjectEquals mMatchHandlerWhatAndObjectEquals = - new MatchHandlerWhatAndObjectEquals(); - boolean hasEqualMessages(Handler h, int what, Object object) { - if (h == null) { - return false; - } - - return findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals, - false); - } - - private static class MatchHandlerRunnableAndObject extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && m.callback == r && (object == null || m.obj == object)) { - return true; - } - return false; - } - } - private final MatchHandlerRunnableAndObject mMatchHandlerRunnableAndObject = - new MatchHandlerRunnableAndObject(); - - boolean hasMessages(Handler h, Runnable r, Object object) { - if (h == null) { - return false; - } - - return findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, false); - } - - private static class MatchHandler extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h) { - return true; - } - return false; - } - } - private final MatchHandler mMatchHandler = new MatchHandler(); - boolean hasMessages(Handler h) { - if (h == null) { - return false; - } - return findOrRemoveMessages(h, -1, null, null, 0, mMatchHandler, false); - } - - void removeMessages(Handler h, int what, Object object) { - if (h == null) { - return; - } - findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObject, true); - } - - void removeEqualMessages(Handler h, int what, Object object) { - if (h == null) { - return; - } - findOrRemoveMessages(h, what, object, null, 0, mMatchHandlerWhatAndObjectEquals, true); - } - - void removeMessages(Handler h, Runnable r, Object object) { - if (h == null || r == null) { - return; - } - findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObject, true); - } - - private static class MatchHandlerRunnableAndObjectEquals extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && m.callback == r && (object == null || object.equals(m.obj))) { - return true; - } - return false; - } - } - private final MatchHandlerRunnableAndObjectEquals mMatchHandlerRunnableAndObjectEquals = - new MatchHandlerRunnableAndObjectEquals(); - void removeEqualMessages(Handler h, Runnable r, Object object) { - if (h == null || r == null) { - return; - } - findOrRemoveMessages(h, -1, object, r, 0, mMatchHandlerRunnableAndObjectEquals, true); - } - - private static class MatchHandlerAndObject extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && (object == null || m.obj == object)) { - return true; - } - return false; - } - } - private final MatchHandlerAndObject mMatchHandlerAndObject = new MatchHandlerAndObject(); - void removeCallbacksAndMessages(Handler h, Object object) { - if (h == null) { - return; - } - findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObject, true); - } - - private static class MatchHandlerAndObjectEquals extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.target == h && (object == null || object.equals(m.obj))) { - return true; - } - return false; - } - } - private final MatchHandlerAndObjectEquals mMatchHandlerAndObjectEquals = - new MatchHandlerAndObjectEquals(); - void removeCallbacksAndEqualMessages(Handler h, Object object) { - if (h == null) { - return; - } - findOrRemoveMessages(h, -1, object, null, 0, mMatchHandlerAndObjectEquals, true); - } - - private static class MatchAllMessages extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - return true; - } - } - private final MatchAllMessages mMatchAllMessages = new MatchAllMessages(); - private void removeAllMessages() { - findOrRemoveMessages(null, -1, null, null, 0, mMatchAllMessages, true); - } - - private static class MatchAllFutureMessages extends MessageCompare { - @Override - public boolean compareMessage(Message m, Handler h, int what, Object object, Runnable r, - long when) { - if (m.when > when) { - return true; - } - return false; - } - } - private final MatchAllFutureMessages mMatchAllFutureMessages = new MatchAllFutureMessages(); - private void removeAllFutureMessages() { - findOrRemoveMessages(null, -1, null, null, SystemClock.uptimeMillis(), - mMatchAllFutureMessages, true); - } - - @NeverCompile - private void printPriorityQueueNodes() { - Iterator<MessageNode> iterator = mPriorityQueue.iterator(); - - Log.d(TAG, "* Dump priority queue"); - while (iterator.hasNext()) { - MessageNode msgNode = iterator.next(); - Log.d(TAG, "** MessageNode what: " + msgNode.mMessage.what + " when " - + msgNode.mMessage.when + " seq: " + msgNode.mInsertSeq); - } - } - - @NeverCompile - private int dumpPriorityQueue(PriorityQueue<MessageNode> queue, Printer pw, String prefix, - Handler h, int n) { - int count = 0; - long now = SystemClock.uptimeMillis(); - - for (MessageNode msgNode : queue) { - Message msg = msgNode.mMessage; - if (h == null || h == msg.target) { - pw.println(prefix + "Message " + (n + count) + ": " + msg.toString(now)); - } - count++; - } - return count; - } - - @NeverCompile - void dump(Printer pw, String prefix, Handler h) { - long now = SystemClock.uptimeMillis(); - int n = 0; - - pw.println(prefix + "(MessageQueue is using SemiConcurrent implementation)"); - - StackNode node = (StackNode) sState.getVolatile(this); - while (node != null) { - if (node.isMessageNode()) { - Message msg = ((MessageNode) node).mMessage; - if (h == null || h == msg.target) { - pw.println(prefix + "Message " + n + ": " + msg.toString(now)); - } - node = ((MessageNode) node).mNext; - } else { - pw.println(prefix + "State: " + node); - node = null; - } - n++; - } - - synchronized (mPriorityQueue) { - pw.println(prefix + "PriorityQueue Messages: "); - n += dumpPriorityQueue(mPriorityQueue, pw, prefix, h, n); - pw.println(prefix + "AsyncPriorityQueue Messages: "); - n += dumpPriorityQueue(mAsyncPriorityQueue, pw, prefix, h, n); - } - - pw.println(prefix + "(Total messages: " + n + ", polling=" + isPolling() - + ", quitting=" + (boolean) sQuitting.getVolatile(this) + ")"); - } - - @NeverCompile - private int dumpPriorityQueue(PriorityQueue<MessageNode> queue, ProtoOutputStream proto) { - int count = 0; - - for (MessageNode msgNode : queue) { - Message msg = msgNode.mMessage; - msg.dumpDebug(proto, MessageQueueProto.MESSAGES); - count++; - } - return count; - } - - @NeverCompile - void dumpDebug(ProtoOutputStream proto, long fieldId) { - final long messageQueueToken = proto.start(fieldId); - - StackNode node = (StackNode) sState.getVolatile(this); - while (node.isMessageNode()) { - Message msg = ((MessageNode) node).mMessage; - msg.dumpDebug(proto, MessageQueueProto.MESSAGES); - node = ((MessageNode) node).mNext; - } - - synchronized (mPriorityQueue) { - dumpPriorityQueue(mPriorityQueue, proto); - dumpPriorityQueue(mAsyncPriorityQueue, proto); - } - - proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPolling()); - proto.write(MessageQueueProto.IS_QUITTING, (boolean) sQuitting.getVolatile(this)); - proto.end(messageQueueToken); - } - - /** - * Adds a file descriptor listener to receive notification when file descriptor - * related events occur. - * <p> - * If the file descriptor has already been registered, the specified events - * and listener will replace any that were previously associated with it. - * It is not possible to set more than one listener per file descriptor. - * </p><p> - * It is important to always unregister the listener when the file descriptor - * is no longer of use. - * </p> - * - * @param fd The file descriptor for which a listener will be registered. - * @param events The set of events to receive: a combination of the - * {@link OnFileDescriptorEventListener#EVENT_INPUT}, - * {@link OnFileDescriptorEventListener#EVENT_OUTPUT}, and - * {@link OnFileDescriptorEventListener#EVENT_ERROR} event masks. If the requested - * set of events is zero, then the listener is unregistered. - * @param listener The listener to invoke when file descriptor events occur. - * - * @see OnFileDescriptorEventListener - * @see #removeOnFileDescriptorEventListener - */ - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) - public void addOnFileDescriptorEventListener(@NonNull FileDescriptor fd, - @OnFileDescriptorEventListener.Events int events, - @NonNull OnFileDescriptorEventListener listener) { - if (fd == null) { - throw new IllegalArgumentException("fd must not be null"); - } - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - - synchronized (mFileDescriptorRecordsLock) { - updateOnFileDescriptorEventListenerLocked(fd, events, listener); - } - } - - /** - * Removes a file descriptor listener. - * <p> - * This method does nothing if no listener has been registered for the - * specified file descriptor. - * </p> - * - * @param fd The file descriptor whose listener will be unregistered. - * - * @see OnFileDescriptorEventListener - * @see #addOnFileDescriptorEventListener - */ - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) - public void removeOnFileDescriptorEventListener(@NonNull FileDescriptor fd) { - if (fd == null) { - throw new IllegalArgumentException("fd must not be null"); - } - - synchronized (mFileDescriptorRecordsLock) { - updateOnFileDescriptorEventListenerLocked(fd, 0, null); - } - } - - @android.ravenwood.annotation.RavenwoodThrow(blockedBy = android.os.ParcelFileDescriptor.class) - private void updateOnFileDescriptorEventListenerLocked(FileDescriptor fd, int events, - OnFileDescriptorEventListener listener) { - final int fdNum = fd.getInt$(); - - int index = -1; - FileDescriptorRecord record = null; - if (mFileDescriptorRecords != null) { - index = mFileDescriptorRecords.indexOfKey(fdNum); - if (index >= 0) { - record = mFileDescriptorRecords.valueAt(index); - if (record != null && record.mEvents == events) { - return; - } - } - } - - if (events != 0) { - events |= OnFileDescriptorEventListener.EVENT_ERROR; - if (record == null) { - if (mFileDescriptorRecords == null) { - mFileDescriptorRecords = new SparseArray<FileDescriptorRecord>(); - } - record = new FileDescriptorRecord(fd, events, listener); - mFileDescriptorRecords.put(fdNum, record); - } else { - record.mListener = listener; - record.mEvents = events; - record.mSeq += 1; - } - nativeSetFileDescriptorEvents(mPtr, fdNum, events); - } else if (record != null) { - record.mEvents = 0; - mFileDescriptorRecords.removeAt(index); - nativeSetFileDescriptorEvents(mPtr, fdNum, 0); - } - } - - // Called from native code. - private int dispatchEvents(int fd, int events) { - // Get the file descriptor record and any state that might change. - final FileDescriptorRecord record; - final int oldWatchedEvents; - final OnFileDescriptorEventListener listener; - final int seq; - synchronized (mFileDescriptorRecordsLock) { - record = mFileDescriptorRecords.get(fd); - if (record == null) { - return 0; // spurious, no listener registered - } - - oldWatchedEvents = record.mEvents; - events &= oldWatchedEvents; // filter events based on current watched set - if (events == 0) { - return oldWatchedEvents; // spurious, watched events changed - } - - listener = record.mListener; - seq = record.mSeq; - } - - // Invoke the listener outside of the lock. - int newWatchedEvents = listener.onFileDescriptorEvents( - record.mDescriptor, events); - if (newWatchedEvents != 0) { - newWatchedEvents |= OnFileDescriptorEventListener.EVENT_ERROR; - } - - // Update the file descriptor record if the listener changed the set of - // events to watch and the listener itself hasn't been updated since. - if (newWatchedEvents != oldWatchedEvents) { - synchronized (mFileDescriptorRecordsLock) { - int index = mFileDescriptorRecords.indexOfKey(fd); - if (index >= 0 && mFileDescriptorRecords.valueAt(index) == record - && record.mSeq == seq) { - record.mEvents = newWatchedEvents; - if (newWatchedEvents == 0) { - mFileDescriptorRecords.removeAt(index); - } - } - } - } - - // Return the new set of events to watch for native code to take care of. - return newWatchedEvents; - } - - /** - * Callback interface for discovering when a thread is going to block - * waiting for more messages. - */ - public static interface IdleHandler { - /** - * Called when the message queue has run out of messages and will now - * wait for more. Return true to keep your idle handler active, false - * to have it removed. This may be called if there are still messages - * pending in the queue, but they are all scheduled to be dispatched - * after the current time. - */ - boolean queueIdle(); - } - - /** - * A listener which is invoked when file descriptor related events occur. - */ - public interface OnFileDescriptorEventListener { - /** - * File descriptor event: Indicates that the file descriptor is ready for input - * operations, such as reading. - * <p> - * The listener should read all available data from the file descriptor - * then return <code>true</code> to keep the listener active or <code>false</code> - * to remove the listener. - * </p><p> - * In the case of a socket, this event may be generated to indicate - * that there is at least one incoming connection that the listener - * should accept. - * </p><p> - * This event will only be generated if the {@link #EVENT_INPUT} event mask was - * specified when the listener was added. - * </p> - */ - public static final int EVENT_INPUT = 1 << 0; - - /** - * File descriptor event: Indicates that the file descriptor is ready for output - * operations, such as writing. - * <p> - * The listener should write as much data as it needs. If it could not - * write everything at once, then it should return <code>true</code> to - * keep the listener active. Otherwise, it should return <code>false</code> - * to remove the listener then re-register it later when it needs to write - * something else. - * </p><p> - * This event will only be generated if the {@link #EVENT_OUTPUT} event mask was - * specified when the listener was added. - * </p> - */ - public static final int EVENT_OUTPUT = 1 << 1; - - /** - * File descriptor event: Indicates that the file descriptor encountered a - * fatal error. - * <p> - * File descriptor errors can occur for various reasons. One common error - * is when the remote peer of a socket or pipe closes its end of the connection. - * </p><p> - * This event may be generated at any time regardless of whether the - * {@link #EVENT_ERROR} event mask was specified when the listener was added. - * </p> - */ - public static final int EVENT_ERROR = 1 << 2; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, prefix = { "EVENT_" }, value = { - EVENT_INPUT, - EVENT_OUTPUT, - EVENT_ERROR - }) - public @interface Events {} - - /** - * Called when a file descriptor receives events. - * - * @param fd The file descriptor. - * @param events The set of events that occurred: a combination of the - * {@link #EVENT_INPUT}, {@link #EVENT_OUTPUT}, and {@link #EVENT_ERROR} event masks. - * @return The new set of events to watch, or 0 to unregister the listener. - * - * @see #EVENT_INPUT - * @see #EVENT_OUTPUT - * @see #EVENT_ERROR - */ - @Events int onFileDescriptorEvents(@NonNull FileDescriptor fd, @Events int events); - } - - static final class FileDescriptorRecord { - public final FileDescriptor mDescriptor; - public int mEvents; - public OnFileDescriptorEventListener mListener; - public int mSeq; - - public FileDescriptorRecord(FileDescriptor descriptor, - int events, OnFileDescriptorEventListener listener) { - mDescriptor = descriptor; - mEvents = events; - mListener = listener; - } - } -} diff --git a/core/java/android/os/SystemVibratorManager.java b/core/java/android/os/SystemVibratorManager.java index f9935d2870b0..1c3dd9eda5ce 100644 --- a/core/java/android/os/SystemVibratorManager.java +++ b/core/java/android/os/SystemVibratorManager.java @@ -217,7 +217,7 @@ public class SystemVibratorManager extends VibratorManager { new VendorVibrationSessionCallbackDelegate(executor, callback); if (mService == null) { Log.w(TAG, "Failed to start vibration session; no vibrator manager service."); - callbackDelegate.onFinished(VendorVibrationSession.STATUS_UNKNOWN_ERROR); + callbackDelegate.onFinished(VendorVibrationSession.STATUS_UNSUPPORTED); return; } try { diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index 9e7c9f6e5417..d3c677bf8af2 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -4,15 +4,6 @@ container: "system" # keep-sorted start block=yes newline_separated=yes flag { - # Holdback study for concurrent MessageQueue. - # Do not promote beyond trunkfood. - namespace: "system_performance" - name: "message_queue_force_legacy" - description: "Whether to holdback concurrent MessageQueue (force legacy)." - bug: "336880969" -} - -flag { name: "adpf_gpu_report_actual_work_duration" is_exported: true namespace: "game" diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 1a9b42e46a1c..538283e10738 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -153,7 +153,6 @@ public final class Settings { * Output: Nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - @FlaggedApi(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String ACTION_SATELLITE_SETTING = "android.settings.SATELLITE_SETTING"; /** @@ -13018,18 +13017,16 @@ public final class Settings { * false/0. * @hide */ - @Readable public static final String REDACT_OTP_NOTIFICATION_WHILE_CONNECTED_TO_WIFI = "redact_otp_on_wifi"; /** - * Toggle for whether to immediately redact OTP notifications, or require the device to be - * locked for 10 minutes. Defaults to false/0 + * Time (in milliseconds) that the device should need to be locked, in order for an OTP + * notification to be redacted. Default is 10 minutes (600,000 ms) * @hide */ - @Readable - public static final String REDACT_OTP_NOTIFICATION_IMMEDIATELY = - "remove_otp_redaction_delay"; + public static final String OTP_NOTIFICATION_REDACTION_LOCK_TIME = + "otp_redaction_lock_time"; /** * These entries are considered common between the personal and the managed profile, diff --git a/core/java/android/service/credentials/CredentialProviderInfoFactory.java b/core/java/android/service/credentials/CredentialProviderInfoFactory.java index 3cd705a3c19c..2266e961852a 100644 --- a/core/java/android/service/credentials/CredentialProviderInfoFactory.java +++ b/core/java/android/service/credentials/CredentialProviderInfoFactory.java @@ -88,7 +88,7 @@ public final class CredentialProviderInfoFactory { int userId, boolean isSystemProvider, boolean isPrimary) - throws PackageManager.NameNotFoundException { + throws PackageManager.NameNotFoundException, SecurityException, NullPointerException { return create( context, getServiceInfoOrThrow(serviceComponent, userId), @@ -117,7 +117,7 @@ public final class CredentialProviderInfoFactory { boolean disableSystemAppVerificationForTests, boolean isEnabled, boolean isPrimary) - throws SecurityException { + throws SecurityException, NullPointerException { verifyProviderPermission(serviceInfo); if (isSystemProvider) { if (!isValidSystemProvider( @@ -199,7 +199,7 @@ public final class CredentialProviderInfoFactory { } private static CredentialProviderInfo.Builder populateMetadata( - @NonNull Context context, ServiceInfo serviceInfo) { + @NonNull Context context, ServiceInfo serviceInfo) throws NullPointerException { requireNonNull(context, "context must not be null"); final PackageManager pm = context.getPackageManager(); CredentialProviderInfo.Builder builder = new CredentialProviderInfo.Builder(serviceInfo); diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 4011574da879..4cbd5beb3a8c 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -309,6 +309,7 @@ public class ZenModeConfig implements Parcelable { private static final String RULE_ATT_DISABLED_ORIGIN = "disabledOrigin"; private static final String RULE_ATT_LEGACY_SUPPRESSED_EFFECTS = "legacySuppressedEffects"; private static final String RULE_ATT_CONDITION_OVERRIDE = "conditionOverride"; + private static final String RULE_ATT_LAST_ACTIVATION = "lastActivation"; private static final String DEVICE_EFFECT_DISPLAY_GRAYSCALE = "zdeDisplayGrayscale"; private static final String DEVICE_EFFECT_SUPPRESS_AMBIENT_DISPLAY = @@ -1187,11 +1188,7 @@ public class ZenModeConfig implements Parcelable { rt.zenPolicyUserModifiedFields = safeInt(parser, POLICY_USER_MODIFIED_FIELDS, 0); rt.zenDeviceEffectsUserModifiedFields = safeInt(parser, DEVICE_EFFECT_USER_MODIFIED_FIELDS, 0); - Long deletionInstant = tryParseLong( - parser.getAttributeValue(null, RULE_ATT_DELETION_INSTANT), null); - if (deletionInstant != null) { - rt.deletionInstant = Instant.ofEpochMilli(deletionInstant); - } + rt.deletionInstant = safeInstant(parser, RULE_ATT_DELETION_INSTANT, null); if (Flags.modesUi()) { rt.disabledOrigin = safeInt(parser, RULE_ATT_DISABLED_ORIGIN, ORIGIN_UNKNOWN); @@ -1199,6 +1196,9 @@ public class ZenModeConfig implements Parcelable { RULE_ATT_LEGACY_SUPPRESSED_EFFECTS, 0); rt.conditionOverride = safeInt(parser, RULE_ATT_CONDITION_OVERRIDE, ZenRule.OVERRIDE_NONE); + if (Flags.modesCleanupImplicit()) { + rt.lastActivation = safeInstant(parser, RULE_ATT_LAST_ACTIVATION, null); + } } return rt; @@ -1249,10 +1249,7 @@ public class ZenModeConfig implements Parcelable { out.attributeInt(null, POLICY_USER_MODIFIED_FIELDS, rule.zenPolicyUserModifiedFields); out.attributeInt(null, DEVICE_EFFECT_USER_MODIFIED_FIELDS, rule.zenDeviceEffectsUserModifiedFields); - if (rule.deletionInstant != null) { - out.attributeLong(null, RULE_ATT_DELETION_INSTANT, - rule.deletionInstant.toEpochMilli()); - } + writeXmlAttributeInstant(out, RULE_ATT_DELETION_INSTANT, rule.deletionInstant); if (Flags.modesUi()) { out.attributeInt(null, RULE_ATT_DISABLED_ORIGIN, rule.disabledOrigin); out.attributeInt(null, RULE_ATT_LEGACY_SUPPRESSED_EFFECTS, @@ -1260,6 +1257,16 @@ public class ZenModeConfig implements Parcelable { if (rule.conditionOverride == ZenRule.OVERRIDE_ACTIVATE && !forBackup) { out.attributeInt(null, RULE_ATT_CONDITION_OVERRIDE, rule.conditionOverride); } + if (Flags.modesCleanupImplicit()) { + writeXmlAttributeInstant(out, RULE_ATT_LAST_ACTIVATION, rule.lastActivation); + } + } + } + + private static void writeXmlAttributeInstant(TypedXmlSerializer out, String att, + @Nullable Instant instant) throws IOException { + if (instant != null) { + out.attributeLong(null, att, instant.toEpochMilli()); } } @@ -1600,6 +1607,19 @@ public class ZenModeConfig implements Parcelable { return values; } + @Nullable + private static Instant safeInstant(TypedXmlPullParser parser, String att, + @Nullable Instant defValue) { + final String strValue = parser.getAttributeValue(null, att); + if (!TextUtils.isEmpty(strValue)) { + Long longValue = tryParseLong(strValue, null); + if (longValue != null) { + return Instant.ofEpochMilli(longValue); + } + } + return defValue; + } + @Override public int describeContents() { return 0; @@ -2598,6 +2618,18 @@ public class ZenModeConfig implements Parcelable { @ConditionOverride int conditionOverride = OVERRIDE_NONE; + /** + * Last time at which the rule was activated (for any reason, including overrides). + * If {@code null}, the rule has never been activated since its creation. + * + * <p>Note that this was previously untracked, so it will also be {@code null} for rules + * created before we started tracking and never activated since -- make sure to account for + * it, for example by falling back to {@link #creationTime} in logic involving this field. + */ + @Nullable + @FlaggedApi(Flags.FLAG_MODES_CLEANUP_IMPLICIT) + public Instant lastActivation; + public ZenRule() { } public ZenRule(Parcel source) { @@ -2635,24 +2667,29 @@ public class ZenModeConfig implements Parcelable { disabledOrigin = source.readInt(); legacySuppressedEffects = source.readInt(); conditionOverride = source.readInt(); + if (Flags.modesCleanupImplicit()) { + if (source.readInt() == 1) { + lastActivation = Instant.ofEpochMilli(source.readLong()); + } + } } } /** - * Whether this ZenRule can be updated by an app. In general, rules that have been - * customized by the user cannot be further updated by an app, with some exceptions: + * Whether this ZenRule has been customized by the user in any way. + + * <p>In general, rules that have been customized by the user cannot be further updated by + * an app, with some exceptions: * <ul> * <li>Non user-configurable fields, like type, icon, configurationActivity, etc. * <li>Name, if the name was not specifically modified by the user (to support language * switches). * </ul> */ - public boolean canBeUpdatedByApp() { - // The rule is considered updateable if its bitmask has no user modifications, and - // the bitmasks of the policy and device effects have no modification. - return userModifiedFields == 0 - && zenPolicyUserModifiedFields == 0 - && zenDeviceEffectsUserModifiedFields == 0; + public boolean isUserModified() { + return userModifiedFields != 0 + || zenPolicyUserModifiedFields != 0 + || zenDeviceEffectsUserModifiedFields != 0; } @Override @@ -2708,6 +2745,14 @@ public class ZenModeConfig implements Parcelable { dest.writeInt(disabledOrigin); dest.writeInt(legacySuppressedEffects); dest.writeInt(conditionOverride); + if (Flags.modesCleanupImplicit()) { + if (lastActivation != null) { + dest.writeInt(1); + dest.writeLong(lastActivation.toEpochMilli()); + } else { + dest.writeInt(0); + } + } } } @@ -2760,6 +2805,9 @@ public class ZenModeConfig implements Parcelable { if (Flags.modesUi()) { sb.append(",disabledOrigin=").append(disabledOrigin); sb.append(",legacySuppressedEffects=").append(legacySuppressedEffects); + if (Flags.modesCleanupImplicit()) { + sb.append(",lastActivation=").append(lastActivation); + } } return sb.append(']').toString(); @@ -2838,6 +2886,10 @@ public class ZenModeConfig implements Parcelable { && other.disabledOrigin == disabledOrigin && other.legacySuppressedEffects == legacySuppressedEffects && other.conditionOverride == conditionOverride; + if (Flags.modesCleanupImplicit()) { + finalEquals = finalEquals + && Objects.equals(other.lastActivation, lastActivation); + } } return finalEquals; @@ -2846,13 +2898,23 @@ public class ZenModeConfig implements Parcelable { @Override public int hashCode() { if (Flags.modesUi()) { - return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, - component, configurationActivity, pkg, id, enabler, zenPolicy, - zenDeviceEffects, allowManualInvocation, iconResName, - triggerDescription, type, userModifiedFields, - zenPolicyUserModifiedFields, zenDeviceEffectsUserModifiedFields, - deletionInstant, disabledOrigin, legacySuppressedEffects, - conditionOverride); + if (Flags.modesCleanupImplicit()) { + return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, + component, configurationActivity, pkg, id, enabler, zenPolicy, + zenDeviceEffects, allowManualInvocation, iconResName, + triggerDescription, type, userModifiedFields, + zenPolicyUserModifiedFields, zenDeviceEffectsUserModifiedFields, + deletionInstant, disabledOrigin, legacySuppressedEffects, + conditionOverride, lastActivation); + } else { + return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, + component, configurationActivity, pkg, id, enabler, zenPolicy, + zenDeviceEffects, allowManualInvocation, iconResName, + triggerDescription, type, userModifiedFields, + zenPolicyUserModifiedFields, zenDeviceEffectsUserModifiedFields, + deletionInstant, disabledOrigin, legacySuppressedEffects, + conditionOverride); + } } else { return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, component, configurationActivity, pkg, id, enabler, zenPolicy, @@ -3069,6 +3131,7 @@ public class ZenModeConfig implements Parcelable { * @return null if DND is off or describeForeverCondition is false and * DND is on forever (until turned off) */ + // TODO: b/368247671 - Delete when inlining MODES_UI public static String getDescription(Context context, boolean zenOn, ZenModeConfig config, boolean describeForeverCondition) { if (!zenOn || config == null) { diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index d05fa9e43cd4..daa4e8936e95 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -2330,8 +2330,6 @@ public class TelephonyCallback { } public void onCarrierRoamingNtnModeChanged(boolean active) { - if (!Flags.carrierEnabledSatelliteFlag()) return; - CarrierRoamingNtnListener listener = (CarrierRoamingNtnListener) mTelephonyCallbackWeakRef.get(); if (listener == null) return; diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index 2fa56137a8a0..b273a7f7c271 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1071,13 +1071,27 @@ public abstract class Layout { var newBackground = determineContrastingBackgroundColor(index); var hasBgColorChanged = newBackground != bgPaint.getColor(); - if (lineNum != mLastLineNum || hasBgColorChanged) { - // Skip processing if the character is a space or a tap to avoid - // rendering an abrupt, empty rectangle. - if (Character.isWhitespace(mText.charAt(index))) { - return; - } + // Skip processing if the character is a space or a tap to avoid + // rendering an abrupt, empty rectangle. + if (TextLine.isLineEndSpace(mText.charAt(index))) { + return; + } + // To avoid highlighting emoji sequences, we use Extended_Pictgraphs as a + // heuristic. Highlighting is skipped based on code points, not glyph type + // (text vs. color), so emojis with default text presentation are + // intentionally not highlighted (numeric representation with emoji + // presentation are manually excluded). Although we process ZWJ and + // variation selectors within emoji sequences, they should not affect + // highlighting due to their zero-width nature. + var codePoint = Character.codePointAt(mText, index); + var isEmoji = Character.isEmojiComponent(codePoint) + || Character.isExtendedPictographic(codePoint); + if (isEmoji && !isStandardNumber(index)) { + return; + } + + if (lineNum != mLastLineNum || hasBgColorChanged) { // Draw what we have so far, then reset the rect and update its color drawRect(); mLineBackground.set(left, top, right, bottom); @@ -1096,6 +1110,16 @@ public abstract class Layout { drawRect(); } + private boolean isStandardNumber(int index) { + var codePoint = Character.codePointAt(mText, index); + var isNumberSignOrAsterisk = (codePoint >= '0' && codePoint <= '9') + || codePoint == '#' || codePoint == '*'; + var isColoredGlyph = index + 1 < mText.length() + && Character.codePointAt(mText, index + 1) == 0xFE0F; + + return isNumberSignOrAsterisk && !isColoredGlyph; + } + private void drawRect() { if (!mLineBackground.isEmpty()) { mLineBackground.inset(-padding, -padding); @@ -4626,6 +4650,16 @@ public abstract class Layout { * Callback for {@link #forEachCharacterBounds(int, int, int, int, CharacterBoundsListener)} */ private interface CharacterBoundsListener { + /** + * Called for each character with its bounds. + * + * @param index the index of the character + * @param lineNum the line number of the character + * @param left the left edge of the character + * @param top the top edge of the character + * @param right the right edge of the character + * @param bottom the bottom edge of the character + */ void onCharacterBounds(int index, int lineNum, float left, float top, float right, float bottom); diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java index a4c3ed96f2ce..5910434dc692 100644 --- a/core/java/android/util/apk/ApkSignatureVerifier.java +++ b/core/java/android/util/apk/ApkSignatureVerifier.java @@ -260,9 +260,11 @@ public class ApkSignatureVerifier { Certificate[][] nonstreamingCerts = null; int v3BlockId = APK_SIGNATURE_SCHEME_DEFAULT; - // If V4 contains additional signing blocks then we need to always run v2/v3 verifier - // to figure out which block they use. - if (verifyFull || signingInfos.signingInfoBlocks.length > 0) { + // We need to always run v2/v3 verifier to figure out which block they use so we can + // return the past signers as well as the current one - the rotation chain is important + // for many callers who verify the signature origin as well as the apk integrity. + if (android.content.pm.Flags.alwaysLoadPastCertsV4() + || verifyFull || signingInfos.signingInfoBlocks.length > 0) { try { // v4 is an add-on and requires v2 or v3 signature to validate against its // certificate and digest diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index f315f55c7ed4..3229fc63dad1 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -50,6 +50,7 @@ import android.view.accessibility.AccessibilityNodeProvider; import android.view.accessibility.AccessibilityRequestPreparer; import android.view.accessibility.Flags; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; +import android.view.accessibility.IWindowSurfaceInfoCallback; import android.window.ScreenCapture; import com.android.internal.R; @@ -631,6 +632,25 @@ public final class AccessibilityInteractionController { } } + /** + * Provide info for taking a screenshot of this app window. + */ + public void getWindowSurfaceInfoClientThread(IWindowSurfaceInfoCallback callback) { + Message message = PooledLambda.obtainMessage( + AccessibilityInteractionController::getWindowSurfaceInfoUiThread, + this, callback); + mHandler.sendMessage(message); + } + + private void getWindowSurfaceInfoUiThread(IWindowSurfaceInfoCallback callback) { + try { + callback.provideWindowSurfaceInfo(mViewRootImpl.getWindowFlags(), Process.myUid(), + mViewRootImpl.getSurfaceControl()); + } catch (RemoteException re) { + // ignore - the other side will time out + } + } + public void findFocusClientThread(long accessibilityNodeId, int focusType, Region interactiveRegion, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, int interrogatingPid, diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index c174fbe0bbcd..3659e785f590 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1299,7 +1299,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation // Handle the pending show request for other insets types since the IME insets // has being requested hidden. handlePendingControlRequest(statsToken); - getImeSourceConsumer().removeSurface(); + if (!Flags.refactorInsetsController()) { + // the surface can't be removed until the end of the animation. This is handled by + // IMMS after the window was requested to be hidden. + getImeSourceConsumer().removeSurface(); + } } applyAnimation(typesReady, false /* show */, fromIme, false /* skipsCallbacks */, statsToken); diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index 73cd5ecd39ef..fe868e1c43be 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -32,7 +32,6 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; -import android.util.TypedValue; import android.widget.FrameLayout; import android.widget.RelativeLayout; import android.widget.RemoteViews; @@ -224,8 +223,14 @@ public class NotificationHeaderView extends RelativeLayout { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (notificationsRedesignTemplates()) { - mTopLineTranslation = measureCenterTranslation(mTopLineView); - mExpandButtonTranslation = measureCenterTranslation(mExpandButton); + // TODO: b/378660052 - These should never be null in practice, consider using + // requireViewById() in the onFinishInflate. + if (mTopLineView != null) { + mTopLineTranslation = measureCenterTranslation(mTopLineView); + } + if (mExpandButton != null) { + mExpandButtonTranslation = measureCenterTranslation(mExpandButton); + } } } @@ -266,20 +271,14 @@ public class NotificationHeaderView extends RelativeLayout { ? R.style.TextAppearance_DeviceDefault_Notification_Title : R.style.TextAppearance_DeviceDefault_Notification_Info; // Most of the time, we're showing text in the minimized state - if (findViewById(R.id.header_text) instanceof TextView headerText) { - headerText.setTextAppearance(styleResId); - if (notificationsRedesignTemplates()) { - // TODO: b/378660052 - When inlining the redesign flag, this should be updated - // directly in TextAppearance_DeviceDefault_Notification_Title so we won't need to - // override it here. - float textSize = getContext().getResources().getDimension( - R.dimen.notification_2025_title_text_size); - headerText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); - } + View headerText = findViewById(R.id.header_text); + if (headerText instanceof TextView) { + ((TextView) headerText).setTextAppearance(styleResId); } // If there's no summary or text, we show the app name instead of nothing - if (findViewById(R.id.app_name_text) instanceof TextView appNameText) { - appNameText.setTextAppearance(styleResId); + View appNameText = findViewById(R.id.app_name_text); + if (appNameText instanceof TextView) { + ((TextView) appNameText).setTextAppearance(styleResId); } } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0866e0d832b1..c048d7987515 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -66,6 +66,7 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; import static com.android.window.flags.Flags.FLAG_DELEGATE_UNHANDLED_DRAGS; import static com.android.window.flags.Flags.FLAG_SUPPORTS_DRAG_ASSISTANT_TO_MULTIWINDOW; +import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs; import static java.lang.Math.max; @@ -247,6 +248,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; @@ -12888,15 +12890,20 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (rects.isEmpty() && mListenerInfo == null) return; final ListenerInfo info = getListenerInfo(); + final boolean rectsChanged = !reduceChangedExclusionRectsMsgs() + || !Objects.equals(info.mSystemGestureExclusionRects, rects); if (info.mSystemGestureExclusionRects != null) { - info.mSystemGestureExclusionRects.clear(); - info.mSystemGestureExclusionRects.addAll(rects); + if (rectsChanged) { + info.mSystemGestureExclusionRects.clear(); + info.mSystemGestureExclusionRects.addAll(rects); + } } else { info.mSystemGestureExclusionRects = new ArrayList<>(rects); } - - updatePositionUpdateListener(); - postUpdate(this::updateSystemGestureExclusionRects); + if (rectsChanged) { + updatePositionUpdateListener(); + postUpdate(this::updateSystemGestureExclusionRects); + } } private void updatePositionUpdateListener() { diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 6b6147a3749d..9498407fb33b 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -136,6 +136,7 @@ import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme; import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay; import static com.android.window.flags.Flags.enableWindowContextResourcesUpdateOnConfigChange; import static com.android.window.flags.Flags.predictiveBackSwipeEdgeNoneApi; +import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs; import static com.android.window.flags.Flags.setScPropertiesInClient; import android.Manifest; @@ -152,8 +153,6 @@ import android.annotation.UiContext; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.ResourcesManager; -import android.app.UiModeManager; -import android.app.UiModeManager.ForceInvertStateChangeListener; import android.app.WindowConfiguration; import android.app.compat.CompatChanges; import android.app.servertransaction.WindowStateTransactionItem; @@ -169,6 +168,7 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.database.ContentObserver; import android.graphics.BLASTBufferQueue; import android.graphics.Canvas; import android.graphics.Color; @@ -214,6 +214,7 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.Vibrator; +import android.provider.Settings; import android.sysprop.DisplayProperties; import android.sysprop.ViewProperties; import android.text.TextUtils; @@ -254,6 +255,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityEmbeddedConnection; import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; +import android.view.accessibility.IWindowSurfaceInfoCallback; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; import android.view.autofill.AutofillManager; @@ -468,8 +470,10 @@ public final class ViewRootImpl implements ViewParent, private CompatOnBackInvokedCallback mCompatOnBackInvokedCallback; @Nullable - private ForceInvertStateChangeListener mForceInvertStateChangeListener; + private ContentObserver mForceInvertObserver; + private static final int INVALID_VALUE = Integer.MIN_VALUE; + private int mForceInvertEnabled = INVALID_VALUE; /** * Callback for notifying about global configuration changes. */ @@ -551,8 +555,6 @@ public final class ViewRootImpl implements ViewParent, @UiContext public final Context mContext; - private UiModeManager mUiModeManager; - @UnsupportedAppUsage final IWindowSession mWindowSession; @NonNull Display mDisplay; @@ -1254,7 +1256,6 @@ public final class ViewRootImpl implements ViewParent, public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session, WindowLayout windowLayout) { mContext = context; - mUiModeManager = context.getSystemService(UiModeManager.class); mWindowSession = session; mWindowLayout = windowLayout; mDisplay = display; @@ -1803,6 +1804,23 @@ public final class ViewRootImpl implements ViewParent, } } + private boolean isForceInvertEnabled() { + if (mForceInvertEnabled == INVALID_VALUE) { + reloadForceInvertEnabled(); + } + return mForceInvertEnabled == 1; + } + + private void reloadForceInvertEnabled() { + if (forceInvertColor()) { + mForceInvertEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, + /* def= */ 0, + UserHandle.myUserId()); + } + } + /** * Register any kind of listeners if setView was success. */ @@ -1834,11 +1852,21 @@ public final class ViewRootImpl implements ViewParent, mBasePackageName); if (forceInvertColor()) { - if (mForceInvertStateChangeListener == null) { - mForceInvertStateChangeListener = - forceInvertState -> updateForceDarkMode(); - mUiModeManager.addForceInvertStateChangeListener(mExecutor, - mForceInvertStateChangeListener); + if (mForceInvertObserver == null) { + mForceInvertObserver = new ContentObserver(mHandler) { + @Override + public void onChange(boolean selfChange) { + reloadForceInvertEnabled(); + updateForceDarkMode(); + } + }; + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED + ), + false, + mForceInvertObserver, + UserHandle.myUserId()); } } } @@ -1856,10 +1884,9 @@ public final class ViewRootImpl implements ViewParent, .unregisterDisplayListener(mDisplayListener); if (forceInvertColor()) { - if (mForceInvertStateChangeListener != null) { - mUiModeManager.removeForceInvertStateChangeListener( - mForceInvertStateChangeListener); - mForceInvertStateChangeListener = null; + if (mForceInvertObserver != null) { + mContext.getContentResolver().unregisterContentObserver(mForceInvertObserver); + mForceInvertObserver = null; } } @@ -2046,25 +2073,21 @@ public final class ViewRootImpl implements ViewParent, return getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; } - /** - * Determines the type of force dark to apply, considering force inversion, system night mode, - * and app-specific settings (including developer opt-outs). - * - * @return A {@link ForceDarkType.ForceDarkTypeDef} constant indicating the force dark type. - */ + /** Returns true if force dark should be enabled according to various settings */ @VisibleForTesting public @ForceDarkType.ForceDarkTypeDef int determineForceDarkType() { if (forceInvertColor()) { // Force invert ignores all developer opt-outs. // We also ignore dark theme, since the app developer can override the user's preference - // for dark mode in configuration.uiMode. Instead, we assume that both force invert and - // the system's dark theme are enabled. - if (mUiModeManager.getForceInvertState() == UiModeManager.FORCE_INVERT_TYPE_DARK) { + // for dark mode in configuration.uiMode. Instead, we assume that the force invert + // setting will be enabled at the same time dark theme is in the Settings app. + if (isForceInvertEnabled()) { return ForceDarkType.FORCE_INVERT_COLOR_DARK; } } boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES; + if (useAutoDark) { boolean forceDarkAllowedDefault = SystemProperties.getBoolean(ThreadedRenderer.DEBUG_FORCE_DARK, false); @@ -6052,8 +6075,12 @@ public final class ViewRootImpl implements ViewParent, } void updateSystemGestureExclusionRectsForView(View view) { + boolean msgInQueue = reduceChangedExclusionRectsMsgs() + && mGestureExclusionTracker.isWaitingForComputeChanges(); mGestureExclusionTracker.updateRectsForView(view); - mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + if (!msgInQueue) { + mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + } } void systemGestureExclusionChanged() { @@ -6097,8 +6124,12 @@ public final class ViewRootImpl implements ViewParent, * the root's view hierarchy. */ public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) { + boolean msgInQueue = reduceChangedExclusionRectsMsgs() + && mGestureExclusionTracker.isWaitingForComputeChanges(); mGestureExclusionTracker.setRootRects(rects); - mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + if (!msgInQueue) { + mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED); + } } /** @@ -12285,6 +12316,15 @@ public final class ViewRootImpl implements ViewParent, } } + @Override + public void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback) { + ViewRootImpl viewRootImpl = mViewRootImpl.get(); + if (viewRootImpl != null && viewRootImpl.mView != null) { + viewRootImpl.getAccessibilityInteractionController() + .getWindowSurfaceInfoClientThread(callback); + } + } + public void attachAccessibilityOverlayToWindow( SurfaceControl sc, int interactionId, diff --git a/core/java/android/view/ViewRootRectTracker.java b/core/java/android/view/ViewRootRectTracker.java index 152729b8d1d8..0bef3255f1dc 100644 --- a/core/java/android/view/ViewRootRectTracker.java +++ b/core/java/android/view/ViewRootRectTracker.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Rect; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.lang.ref.WeakReference; @@ -32,8 +33,10 @@ import java.util.function.Function; /** * Abstract class to track a collection of rects reported by the views under the same * {@link ViewRootImpl}. + * @hide */ -class ViewRootRectTracker { +@VisibleForTesting +public class ViewRootRectTracker { private final Function<View, List<Rect>> mRectCollector; private boolean mViewsChanged = false; private boolean mRootRectsChanged = false; @@ -41,11 +44,18 @@ class ViewRootRectTracker { private List<ViewInfo> mViewInfos = new ArrayList<>(); private List<Rect> mRects = Collections.emptyList(); + // Keeps track of whether updateRectsForView has been called but there was no subsequent call + // on computeChanges yet. Since updateRectsForView is called when sending a message and + // computeChanges when it is received, this tracks whether such message is in the queue already + private boolean mWaitingForComputeChanges = false; + /** * @param rectCollector given a view returns a list of the rects of interest for this * ViewRootRectTracker + * @hide */ - ViewRootRectTracker(Function<View, List<Rect>> rectCollector) { + @VisibleForTesting + public ViewRootRectTracker(Function<View, List<Rect>> rectCollector) { mRectCollector = rectCollector; } @@ -70,6 +80,7 @@ class ViewRootRectTracker { mViewInfos.add(new ViewInfo(view)); mViewsChanged = true; } + mWaitingForComputeChanges = true; } /** @@ -92,6 +103,7 @@ class ViewRootRectTracker { * @return {@code true} if there were changes, {@code false} otherwise. */ public boolean computeChanges() { + mWaitingForComputeChanges = false; boolean changed = mRootRectsChanged; final Iterator<ViewInfo> i = mViewInfos.iterator(); final List<Rect> rects = new ArrayList<>(mRootRects); @@ -121,6 +133,10 @@ class ViewRootRectTracker { return false; } + public boolean isWaitingForComputeChanges() { + return mWaitingForComputeChanges; + } + /** * Returns a List of all Rects from all visible Views in the global (root) coordinate system. * This list is only updated when calling {@link #computeChanges()} or @@ -140,6 +156,7 @@ class ViewRootRectTracker { Preconditions.checkNotNull(rects, "rects must not be null"); mRootRects = rects; mRootRectsChanged = true; + mWaitingForComputeChanges = true; } @NonNull diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java index e3ea6b229d64..a952967f4daf 100644 --- a/core/java/android/view/WindowInsets.java +++ b/core/java/android/view/WindowInsets.java @@ -1290,7 +1290,8 @@ public final class WindowInsets { int newTop = Math.max(0, insets.top - top); int newRight = Math.max(0, insets.right - right); int newBottom = Math.max(0, insets.bottom - bottom); - if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) { + if (newLeft == insets.left && newTop == insets.top + && newRight == insets.right && newBottom == insets.bottom) { return insets; } return Insets.of(newLeft, newTop, newRight, newBottom); diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl index a43acf9147f3..ca024fd03778 100644 --- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl +++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl @@ -23,6 +23,7 @@ import android.view.MagnificationSpec; import android.view.SurfaceControl; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; +import android.view.accessibility.IWindowSurfaceInfoCallback; import android.window.ScreenCapture; /** @@ -67,5 +68,7 @@ oneway interface IAccessibilityInteractionConnection { in ScreenCapture.ScreenCaptureListener listener, IAccessibilityInteractionConnectionCallback callback); + void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback); + void attachAccessibilityOverlayToWindow(in SurfaceControl sc, int interactionId, in IAccessibilityInteractionConnectionCallback callback); } diff --git a/core/java/android/view/accessibility/IWindowSurfaceInfoCallback.aidl b/core/java/android/view/accessibility/IWindowSurfaceInfoCallback.aidl new file mode 100644 index 000000000000..370f185b5596 --- /dev/null +++ b/core/java/android/view/accessibility/IWindowSurfaceInfoCallback.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.accessibility; + +import android.view.SurfaceControl; + +/** + * Callback for an app to provide AbstractAccessibilityServiceConnection with window and surface + * information necessary for system_server to take a screenshot of the app window. + * @hide + */ +oneway interface IWindowSurfaceInfoCallback { + + /** + * Provide info from ViewRootImpl for taking a screenshot of this app window. + * + * @param windowFlags the window flags of ViewRootImpl + * @param processUid the process (kernel) uid, NOT the user ID, required for + SurfaceFlinger screenshots + * @param surfaceControl the surface of ViewRootImpl + */ + @RequiresNoPermission + void provideWindowSurfaceInfo(int windowFlags, int processUid, + in SurfaceControl surfaceControl); +} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 56f0415b40cc..421001f385d4 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -466,6 +466,26 @@ public final class InputMethodManager { private static final long USE_ASYNC_SHOW_HIDE_METHOD = 352594277L; // This is a bug id. /** + * Always return {@code true} when {@link #hideSoftInputFromWindow(IBinder, int)} and + * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver, int, ImeTracker.Token)} is + * called. + * <p> + * Apps can incorrectly rely on the return value of + * {@link #hideSoftInputFromWindow(IBinder, int)} to guess whether the IME was hidden. + * However, it was never a guarantee that the IME will actually hide. + * Therefore, it was recommended using the {@link View.OnApplyWindowInsetsListener}. + * <p> + * Starting Android {@link Build.VERSION_CODES.BAKLAVA}, the return value will always be + * true, independent from whether the request was eventually sent to system server or not. + * Apps that need to know when the IME visibility changes should use + * {@link View.OnApplyWindowInsetsListener}. For apps that target earlier releases, it + * returns an estimate ({@code true} if the IME was showing before). + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA) + private static final long ALWAYS_RETURN_TRUE_HIDE_SOFT_INPUT_FROM_WINDOW = 395521150L; // bug id + + /** * If {@code true}, avoid calling the * {@link com.android.server.inputmethod.InputMethodManagerService InputMethodManagerService} * by skipping the call to {@link IInputMethodManager#startInputOrWindowGainedFocus} @@ -2531,9 +2551,14 @@ public final class InputMethodManager { * * @param windowToken The token of the window that is making the request, * as returned by {@link View#getWindowToken() View.getWindowToken()}. - * @return {@code true} if a request was sent to system_server, {@code false} otherwise. Note: - * this does not return result of the request. For result use {@link ResultReceiver} in - * {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)} instead. + * @return <p>For apps targeting Android {@link Build.VERSION_CODES.BAKLAVA}, onwards, it + * will always return {@code true}. To see when the IME is hidden, use + * {@link View.OnApplyWindowInsetsListener} and verify the provided {@link WindowInsets} for + * the visibility of IME. + * + * <p>For apps targeting releases before Android Baklava: returns {@code true} if a request + * was sent to system_server, {@code false} otherwise. Note: This does not return the result + * of that request (i.e. whether the IME was actually hidden). */ public boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags) { return hideSoftInputFromWindow(windowToken, flags, null); @@ -2563,7 +2588,8 @@ public final class InputMethodManager { * {@link #RESULT_UNCHANGED_HIDDEN}, {@link #RESULT_SHOWN}, or * {@link #RESULT_HIDDEN}. * @return {@code true} if a request was sent to system_server, {@code false} otherwise. Note: - * this does not return result of the request. For result use {@param resultReceiver} instead. + * This does not return the result of that request (i.e. whether the IME was actually hidden). + * For result use {@param resultReceiver} instead. * * @deprecated The {@link ResultReceiver} is not a reliable way of determining whether the * Input Method is actually shown or hidden. If result is needed, use @@ -2603,7 +2629,10 @@ public final class InputMethodManager { ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED); ImeTracker.forLatency().onHideFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication); - return false; + // with the flag enabled and targeting Android Baklava onwards, the return value + // should be always true (was false before). + return Flags.refactorInsetsController() && CompatChanges.isChangeEnabled( + ALWAYS_RETURN_TRUE_HIDE_SOFT_INPUT_FROM_WINDOW); } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED); @@ -2618,15 +2647,18 @@ public final class InputMethodManager { // under us. The current input has been closed before (from checkFocus). ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_HANDLER_AVAILABLE); - return false; + // with the flag enabled and targeting Android Baklava onwards, the + // return value should be always true (was false before). + return Flags.refactorInsetsController() && CompatChanges.isChangeEnabled( + ALWAYS_RETURN_TRUE_HIDE_SOFT_INPUT_FROM_WINDOW); } ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_CLIENT_VIEW_HANDLER_AVAILABLE); + final boolean imeReqVisible = + (viewRootImpl.getInsetsController().getRequestedVisibleTypes() + & WindowInsets.Type.ime()) != 0; if (resultReceiver != null) { - final boolean imeReqVisible = - (viewRootImpl.getInsetsController().getRequestedVisibleTypes() - & WindowInsets.Type.ime()) != 0; resultReceiver.send( !imeReqVisible ? InputMethodManager.RESULT_UNCHANGED_HIDDEN : InputMethodManager.RESULT_HIDDEN, null); @@ -2642,8 +2674,16 @@ public final class InputMethodManager { viewRootImpl.getInsetsController().hide(WindowInsets.Type.ime(), false /* fromIme */, statsToken); } + if (!CompatChanges.isChangeEnabled( + ALWAYS_RETURN_TRUE_HIDE_SOFT_INPUT_FROM_WINDOW)) { + // if the IME was not visible before, the additional hide won't change + // anything. + return imeReqVisible; + } } - return true; + // Targeting Android Baklava onwards, this method will always return true. + return CompatChanges.isChangeEnabled( + ALWAYS_RETURN_TRUE_HIDE_SOFT_INPUT_FROM_WINDOW); } else { return IInputMethodManagerGlobalInvoker.hideSoftInput(mClient, windowToken, statsToken, flags, resultReceiver, reason, mAsyncShowHideMethodEnabled); diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java index d43469fa76ca..4ba97384192f 100644 --- a/core/java/android/window/DesktopModeFlags.java +++ b/core/java/android/window/DesktopModeFlags.java @@ -96,13 +96,16 @@ public enum DesktopModeFlags { ENABLE_DESKTOP_WINDOWING_TASK_LIMIT(Flags::enableDesktopWindowingTaskLimit, true), ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY(Flags::enableDesktopWindowingWallpaperActivity, true), + ENABLE_DRAG_RESIZE_SET_UP_IN_BG_THREAD(Flags::enableDragResizeSetUpInBgThread, false), ENABLE_FULLY_IMMERSIVE_IN_DESKTOP(Flags::enableFullyImmersiveInDesktop, true), ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true), ENABLE_HOLD_TO_DRAG_APP_HANDLE(Flags::enableHoldToDragAppHandle, true), ENABLE_MINIMIZE_BUTTON(Flags::enableMinimizeButton, true), + ENABLE_MODALS_FULLSCREEN_WITH_PERMISSIONS(Flags::enableModalsFullscreenWithPermission, false), ENABLE_RESIZING_METRICS(Flags::enableResizingMetrics, true), ENABLE_RESTORE_TO_PREVIOUS_SIZE_FROM_DESKTOP_IMMERSIVE( Flags::enableRestoreToPreviousSizeFromDesktopImmersive, true), + ENABLE_TASKBAR_OVERFLOW(Flags::enableTaskbarOverflow, false), ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS(Flags::enableTaskResizingKeyboardShortcuts, true), ENABLE_TASK_STACK_OBSERVER_IN_SHELL(Flags::enableTaskStackObserverInShell, true), ENABLE_THEMED_APP_HEADERS(Flags::enableThemedAppHeaders, true), @@ -114,6 +117,7 @@ public enum DesktopModeFlags { ENABLE_WINDOWING_SCALED_RESIZING(Flags::enableWindowingScaledResizing, true), ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS( Flags::enableWindowingTransitionHandlersObservers, false), + EXCLUDE_CAPTION_FROM_APP_BOUNDS(Flags::excludeCaptionFromAppBounds, false), INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC( Flags::includeTopTransparentFullscreenTaskInDesktopHeuristic, true) // go/keep-sorted end diff --git a/core/java/android/window/SystemUiContext.java b/core/java/android/window/SystemUiContext.java new file mode 100644 index 000000000000..1e9a7203c09f --- /dev/null +++ b/core/java/android/window/SystemUiContext.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.window; + +import android.annotation.NonNull; +import android.content.ComponentCallbacks; +import android.content.ComponentCallbacksController; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.Configuration; + +import com.android.window.flags.Flags; + +/** + * System Context to be used for UI. This Context has resources that can be themed. + * + * @see android.app.ActivityThread#getSystemUiContext(int) + * + * @hide + */ +public class SystemUiContext extends ContextWrapper implements ConfigurationDispatcher { + + private final ComponentCallbacksController mCallbacksController = + new ComponentCallbacksController(); + + public SystemUiContext(Context base) { + super(base); + if (!Flags.trackSystemUiContextBeforeWms()) { + throw new UnsupportedOperationException("SystemUiContext can only be used after" + + " flag is enabled."); + } + } + + @Override + public void registerComponentCallbacks(@NonNull ComponentCallbacks callback) { + mCallbacksController.registerCallbacks(callback); + } + + @Override + public void unregisterComponentCallbacks(@NonNull ComponentCallbacks callback) { + mCallbacksController.unregisterCallbacks(callback); + } + + /** Dispatch {@link Configuration} to each {@link ComponentCallbacks}. */ + @Override + public void dispatchConfigurationChanged(@NonNull Configuration newConfig) { + mCallbacksController.dispatchConfigurationChanged(newConfig); + } + + @Override + public boolean shouldReportPrivateChanges() { + // We should report all config changes to update fields obtained from resources. + return true; + } +} diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index e358540afe6b..8265d2523d6f 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -16,6 +16,17 @@ flag { } flag { + name: "enable_modals_fullscreen_with_permission" + namespace: "lse_desktop_experience" + description: "Uses permissions to understand if modal fullscreen is allowed for /n" + "transparent activities." + bug: "394714626" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "include_top_transparent_fullscreen_task_in_desktop_heuristic" namespace: "lse_desktop_experience" description: "Whether to include any top transparent fullscreen task launched in desktop /n" @@ -79,6 +90,16 @@ flag { } flag { + name: "enable_drag_resize_set_up_in_bg_thread" + namespace: "lse_desktop_experience" + description: "Enables setting up the drag-resize input listener in a bg thread" + bug: "396445663" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "enable_desktop_windowing_wallpaper_activity" namespace: "lse_desktop_experience" description: "Enables desktop wallpaper activity to show wallpaper in the desktop mode" @@ -175,6 +196,16 @@ flag { } flag { + name: "enable_camera_compat_for_desktop_windowing_opt_out" + namespace: "lse_desktop_experience" + description: "Whether to allow developers to opt-out of Camera Compat treatment to fixed-orientation apps in desktop windowing mode" + bug: "328616176" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "enable_task_stack_observer_in_shell" namespace: "lse_desktop_experience" description: "Introduces a new observer in shell to track the task stack." @@ -674,6 +705,13 @@ flag { } flag { + name: "enable_activity_embedding_support_for_connected_displays" + namespace: "lse_desktop_experience" + description: "Enables activity embedding support for connected displays, including enabling AE optimization for Settings." + bug: "369438353" +} + +flag { name: "enable_full_screen_window_on_removing_split_screen_stage_bugfix" namespace: "lse_desktop_experience" description: "Enables clearing the windowing mode of a freeform window when removing the task from the split screen stage." @@ -733,3 +771,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "enable_taskbar_overflow" + namespace: "lse_desktop_experience" + description: "Show recent apps in the taskbar overflow." + bug: "368119679" +} diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 25dc6723aa78..a4d128fa3caf 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -40,6 +40,17 @@ flag { } flag { + name: "cache_window_style" + namespace: "windowing_frontend" + description: "Cache common window styles" + bug: "350394503" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "edge_to_edge_by_default" namespace: "windowing_frontend" description: "Make app go edge-to-edge by default when targeting SDK 35 or greater" @@ -417,6 +428,17 @@ flag { } flag { + name: "reduce_changed_exclusion_rects_msgs" + namespace: "windowing_frontend" + description: "Don't send MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED when there is no change" + bug: "388231176" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "keep_app_window_hide_while_locked" namespace: "windowing_frontend" description: "Do not let app window visible while device is locked" diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 3bdf3d65e99c..c009fc3b7e63 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1875,9 +1875,7 @@ public class ChooserActivity extends ResolverActivity implements Bundle b = new Bundle(); // Add userHandle based badge to the stackedAppDialogBox. b.putParcelable(ChooserTargetActionsDialogFragment.USER_HANDLE_KEY, - getResolveInfoUserHandle( - targetInfo.getResolveInfo(), - mChooserMultiProfilePagerAdapter.getCurrentUserHandle())); + targetInfo.getResolveInfo().userHandle); b.putObject(ChooserStackedAppDialogFragment.MULTI_DRI_KEY, mti); b.putInt(ChooserStackedAppDialogFragment.WHICH_KEY, which); @@ -2457,10 +2455,7 @@ public class ChooserActivity extends ResolverActivity implements // compares using resolveInfo.userHandle mComparator = Comparator.comparing(DisplayResolveInfo::getDisplayLabel, collator) .thenComparingInt(displayResolveInfo -> - getResolveInfoUserHandle( - displayResolveInfo.getResolveInfo(), - // TODO: User resolveInfo.userHandle, once its available. - UserHandle.SYSTEM).getIdentifier()); + displayResolveInfo.getResolveInfo().userHandle.getIdentifier()); } @Override diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index b3e828d15737..d38689c7505b 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -362,8 +362,7 @@ public class ChooserListAdapter extends ResolverListAdapter { } String resolvedTarget = info.getResolvedComponentName().getPackageName() + '#' + info.getDisplayLabel() - + '#' + ResolverActivity.getResolveInfoUserHandle( - info.getResolveInfo(), getUserHandle()).getIdentifier(); + + '#' + info.getResolveInfo().userHandle.getIdentifier(); DisplayResolveInfo multiDri = consolidated.get(resolvedTarget); if (multiDri == null) { consolidated.put(resolvedTarget, info); diff --git a/core/java/com/android/internal/app/MediaRouteControllerContentManager.java b/core/java/com/android/internal/app/MediaRouteControllerContentManager.java new file mode 100644 index 000000000000..dc4caa3d35d7 --- /dev/null +++ b/core/java/com/android/internal/app/MediaRouteControllerContentManager.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.app; + +import android.content.Context; +import android.media.MediaRouter; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.SeekBar; + +import com.android.internal.R; + +/** + * This class manages the content display within the media route controller UI. + */ +public class MediaRouteControllerContentManager { + /** + * A delegate interface that a MediaRouteController UI should implement. It allows the content + * manager to inform the UI of any UI changes that need to be made in response to content + * updates. + */ + public interface Delegate { + /** + * Updates the title of the cast device + */ + void setCastDeviceTitle(CharSequence title); + + /** + * Dismiss the UI to transition to a different workflow. + */ + void dismissView(); + } + + private final Delegate mDelegate; + + // Time to wait before updating the volume when the user lets go of the seek bar + // to allow the route provider time to propagate the change and publish a new + // route descriptor. + private static final int VOLUME_UPDATE_DELAY_MILLIS = 250; + + private final MediaRouter mRouter; + private final MediaRouter.RouteInfo mRoute; + + private LinearLayout mVolumeLayout; + private SeekBar mVolumeSlider; + private boolean mVolumeSliderTouched; + + public MediaRouteControllerContentManager(Context context, Delegate delegate) { + mDelegate = delegate; + mRouter = context.getSystemService(MediaRouter.class); + mRoute = mRouter.getSelectedRoute(); + } + + /** + * Starts binding all the views (volume layout, slider, etc.) using the + * given container view. + */ + public void bindViews(View containerView) { + mDelegate.setCastDeviceTitle(mRoute.getName()); + mVolumeLayout = containerView.findViewById(R.id.media_route_volume_layout); + mVolumeSlider = containerView.findViewById(R.id.media_route_volume_slider); + mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + private final Runnable mStopTrackingTouch = new Runnable() { + @Override + public void run() { + if (mVolumeSliderTouched) { + mVolumeSliderTouched = false; + updateVolume(); + } + } + }; + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + if (mVolumeSliderTouched) { + mVolumeSlider.removeCallbacks(mStopTrackingTouch); + } else { + mVolumeSliderTouched = true; + } + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Defer resetting mVolumeSliderTouched to allow the media route provider + // a little time to settle into its new state and publish the final + // volume update. + mVolumeSlider.postDelayed(mStopTrackingTouch, VOLUME_UPDATE_DELAY_MILLIS); + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser) { + mRoute.requestSetVolume(progress); + } + } + }); + } + + /** + * Updates all the views to reflect new states. + */ + public void update() { + mDelegate.setCastDeviceTitle(mRoute.getName()); + updateVolume(); + } + + /** + * Updates the volume layout and slider. + */ + public void updateVolume() { + if (!mVolumeSliderTouched) { + if (isVolumeControlAvailable()) { + mVolumeLayout.setVisibility(View.VISIBLE); + mVolumeSlider.setMax(mRoute.getVolumeMax()); + mVolumeSlider.setProgress(mRoute.getVolume()); + } else { + mVolumeLayout.setVisibility(View.GONE); + } + } + } + + /** + * Callback function to triggered after the disconnect button is clicked. + */ + public void onDisconnectButtonClick() { + if (mRoute.isSelected()) { + if (mRoute.isBluetooth()) { + mRouter.getDefaultRoute().select(); + } else { + mRouter.getFallbackRoute().select(); + } + } + mDelegate.dismissView(); + } + + private boolean isVolumeControlAvailable() { + return mRoute.getVolumeHandling() == MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE; + } +} diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialog.java b/core/java/com/android/internal/app/MediaRouteControllerDialog.java index 61e63d1b30de..45a4a13667a4 100644 --- a/core/java/com/android/internal/app/MediaRouteControllerDialog.java +++ b/core/java/com/android/internal/app/MediaRouteControllerDialog.java @@ -16,13 +16,10 @@ package com.android.internal.app; -import com.android.internal.R; - import android.app.AlertDialog; import android.app.MediaRouteActionProvider; import android.app.MediaRouteButton; import android.content.Context; -import android.content.DialogInterface; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.drawable.AnimationDrawable; @@ -35,9 +32,8 @@ import android.os.Bundle; import android.util.TypedValue; import android.view.KeyEvent; import android.view.View; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.SeekBar; + +import com.android.internal.R; /** * This class implements the route controller dialog for {@link MediaRouter}. @@ -50,167 +46,49 @@ import android.widget.SeekBar; * * TODO: Move this back into the API, as in the support library media router. */ -public class MediaRouteControllerDialog extends AlertDialog { - // Time to wait before updating the volume when the user lets go of the seek bar - // to allow the route provider time to propagate the change and publish a new - // route descriptor. - private static final int VOLUME_UPDATE_DELAY_MILLIS = 250; - +public class MediaRouteControllerDialog extends AlertDialog implements + MediaRouteControllerContentManager.Delegate { + // TODO(b/360050020): Eventually these 3 variables should be in the content manager instead of + // here. So these should be removed when the migration is completed. private final MediaRouter mRouter; private final MediaRouterCallback mCallback; private final MediaRouter.RouteInfo mRoute; - private boolean mCreated; private Drawable mMediaRouteButtonDrawable; private int[] mMediaRouteConnectingState = { R.attr.state_checked, R.attr.state_enabled }; private int[] mMediaRouteOnState = { R.attr.state_activated, R.attr.state_enabled }; private Drawable mCurrentIconDrawable; - private boolean mVolumeControlEnabled = true; - private LinearLayout mVolumeLayout; - private SeekBar mVolumeSlider; - private boolean mVolumeSliderTouched; - - private View mControlView; private boolean mAttachedToWindow; + private final MediaRouteControllerContentManager mContentManager; + public MediaRouteControllerDialog(Context context, int theme) { super(context, theme); + mContentManager = new MediaRouteControllerContentManager(context, this); mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); mCallback = new MediaRouterCallback(); mRoute = mRouter.getSelectedRoute(); } - /** - * Gets the route that this dialog is controlling. - */ - public MediaRouter.RouteInfo getRoute() { - return mRoute; - } - - /** - * Provides the subclass an opportunity to create a view that will - * be included within the body of the dialog to offer additional media controls - * for the currently playing content. - * - * @param savedInstanceState The dialog's saved instance state. - * @return The media control view, or null if none. - */ - public View onCreateMediaControlView(Bundle savedInstanceState) { - return null; - } - - /** - * Gets the media control view that was created by {@link #onCreateMediaControlView(Bundle)}. - * - * @return The media control view, or null if none. - */ - public View getMediaControlView() { - return mControlView; - } - - /** - * Sets whether to enable the volume slider and volume control using the volume keys - * when the route supports it. - * <p> - * The default value is true. - * </p> - */ - public void setVolumeControlEnabled(boolean enable) { - if (mVolumeControlEnabled != enable) { - mVolumeControlEnabled = enable; - if (mCreated) { - updateVolume(); - } - } - } - - /** - * Returns whether to enable the volume slider and volume control using the volume keys - * when the route supports it. - */ - public boolean isVolumeControlEnabled() { - return mVolumeControlEnabled; - } - @Override protected void onCreate(Bundle savedInstanceState) { - setTitle(mRoute.getName()); Resources res = getContext().getResources(); setButton(BUTTON_NEGATIVE, res.getString(R.string.media_route_controller_disconnect), - new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int id) { - if (mRoute.isSelected()) { - if (mRoute.isBluetooth()) { - mRouter.getDefaultRoute().select(); - } else { - mRouter.getFallbackRoute().select(); - } - } - dismiss(); - } - }); + (dialogInterface, id) -> mContentManager.onDisconnectButtonClick()); View customView = getLayoutInflater().inflate(R.layout.media_route_controller_dialog, null); setView(customView, 0, 0, 0, 0); + mContentManager.bindViews(customView); super.onCreate(savedInstanceState); View customPanelView = getWindow().findViewById(R.id.customPanel); if (customPanelView != null) { customPanelView.setMinimumHeight(0); } - mVolumeLayout = (LinearLayout) customView.findViewById(R.id.media_route_volume_layout); - mVolumeSlider = (SeekBar) customView.findViewById(R.id.media_route_volume_slider); - mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - private final Runnable mStopTrackingTouch = new Runnable() { - @Override - public void run() { - if (mVolumeSliderTouched) { - mVolumeSliderTouched = false; - updateVolume(); - } - } - }; - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - if (mVolumeSliderTouched) { - mVolumeSlider.removeCallbacks(mStopTrackingTouch); - } else { - mVolumeSliderTouched = true; - } - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - // Defer resetting mVolumeSliderTouched to allow the media route provider - // a little time to settle into its new state and publish the final - // volume update. - mVolumeSlider.postDelayed(mStopTrackingTouch, VOLUME_UPDATE_DELAY_MILLIS); - } - - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (fromUser) { - mRoute.requestSetVolume(progress); - } - } - }); mMediaRouteButtonDrawable = obtainMediaRouteButtonDrawable(); - mCreated = true; - if (update()) { - mControlView = onCreateMediaControlView(savedInstanceState); - FrameLayout controlFrame = - (FrameLayout) customView.findViewById(R.id.media_route_control_frame); - if (mControlView != null) { - controlFrame.addView(mControlView); - controlFrame.setVisibility(View.VISIBLE); - } else { - controlFrame.setVisibility(View.GONE); - } - } + update(); } @Override @@ -249,20 +127,27 @@ public class MediaRouteControllerDialog extends AlertDialog { return super.onKeyUp(keyCode, event); } - private boolean update() { + @Override + public void setCastDeviceTitle(CharSequence title) { + setTitle(title); + } + + @Override + public void dismissView() { + dismiss(); + } + + private void update() { if (!mRoute.isSelected() || mRoute.isDefault()) { - dismiss(); - return false; + dismissView(); } - setTitle(mRoute.getName()); - updateVolume(); + mContentManager.update(); Drawable icon = getIconDrawable(); if (icon != mCurrentIconDrawable) { mCurrentIconDrawable = icon; - if (icon instanceof AnimationDrawable) { - AnimationDrawable animDrawable = (AnimationDrawable) icon; + if (icon instanceof AnimationDrawable animDrawable) { if (!mAttachedToWindow && !mRoute.isConnecting()) { // When the route is already connected before the view is attached, show the // last frame of the connected animation immediately. @@ -276,7 +161,6 @@ public class MediaRouteControllerDialog extends AlertDialog { } setIcon(icon); } - return true; } private Drawable obtainMediaRouteButtonDrawable() { @@ -306,23 +190,6 @@ public class MediaRouteControllerDialog extends AlertDialog { } } - private void updateVolume() { - if (!mVolumeSliderTouched) { - if (isVolumeControlAvailable()) { - mVolumeLayout.setVisibility(View.VISIBLE); - mVolumeSlider.setMax(mRoute.getVolumeMax()); - mVolumeSlider.setProgress(mRoute.getVolume()); - } else { - mVolumeLayout.setVisibility(View.GONE); - } - } - } - - private boolean isVolumeControlAvailable() { - return mVolumeControlEnabled && mRoute.getVolumeHandling() == - MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE; - } - private final class MediaRouterCallback extends MediaRouter.SimpleCallback { @Override public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { @@ -337,7 +204,7 @@ public class MediaRouteControllerDialog extends AlertDialog { @Override public void onRouteVolumeChanged(MediaRouter router, MediaRouter.RouteInfo route) { if (route == mRoute) { - updateVolume(); + mContentManager.updateVolume(); } } diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS index 52f18fb80c27..0bba24d4ce19 100644 --- a/core/java/com/android/internal/app/OWNERS +++ b/core/java/com/android/internal/app/OWNERS @@ -20,3 +20,6 @@ per-file *VisualQuery* = file:/core/java/android/service/voice/OWNERS # System language settings per-file *Locale* = file:platform/packages/apps/Settings:/src/com/android/settings/localepicker/OWNERS + +# Media +per-file *MediaRoute* = file:/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index db65d31f59da..eaf1573e929f 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -1605,8 +1605,7 @@ public class ResolverActivity extends Activity implements // In case cloned apps are present, we would want to start those apps in cloned user // space, which will not be same as adaptor's userHandle. resolveInfo.userHandle // identifies the correct user space in such cases. - UserHandle activityUserHandle = getResolveInfoUserHandle( - cti.getResolveInfo(), mMultiProfilePagerAdapter.getCurrentUserHandle()); + UserHandle activityUserHandle = cti.getResolveInfo().userHandle; safelyStartActivityAsUser(cti, activityUserHandle, null); } @@ -2399,11 +2398,7 @@ public class ResolverActivity extends Activity implements && Objects.equals(lhs.activityInfo.packageName, rhs.activityInfo.packageName) // Comparing against resolveInfo.userHandle in case cloned apps are present, // as they will have the same activityInfo. - && Objects.equals( - getResolveInfoUserHandle(lhs, - mMultiProfilePagerAdapter.getActiveListAdapter().getUserHandle()), - getResolveInfoUserHandle(rhs, - mMultiProfilePagerAdapter.getActiveListAdapter().getUserHandle())); + && Objects.equals(lhs.userHandle, rhs.userHandle); } protected String getMetricsCategory() { @@ -2686,18 +2681,6 @@ public class ResolverActivity extends Activity implements return userList; } - /** - * This function is temporary in nature, and its usages will be replaced with just - * resolveInfo.userHandle, once it is available, once sharesheet is stable. - */ - public static UserHandle getResolveInfoUserHandle(ResolveInfo resolveInfo, - UserHandle predictedHandle) { - if (resolveInfo.userHandle == null) { - Log.e(TAG, "ResolveInfo with null UserHandle found: " + resolveInfo); - } - return resolveInfo.userHandle; - } - private boolean privateSpaceEnabled() { return mIsIntentPicker && android.os.Flags.allowPrivateProfile() && android.multiuser.Flags.allowResolverSheetForPrivateSpace() diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index de7ad346a7cd..54c0e61fd5cd 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -747,8 +747,7 @@ public class ResolverListAdapter extends BaseAdapter { Drawable loadIconForResolveInfo(ResolveInfo ri) { // Load icons based on userHandle from ResolveInfo. If in work profile/clone profile, icons // should be badged. - return makePresentationGetter(ri) - .getIcon(ResolverActivity.getResolveInfoUserHandle(ri, getUserHandle())); + return makePresentationGetter(ri).getIcon(ri.userHandle); } void loadFilteredItemIconTaskAsync(@NonNull ImageView iconView) { diff --git a/core/java/com/android/internal/os/ApplicationSharedMemory.java b/core/java/com/android/internal/os/ApplicationSharedMemory.java index e6ea29e483f1..4c491c82fd56 100644 --- a/core/java/com/android/internal/os/ApplicationSharedMemory.java +++ b/core/java/com/android/internal/os/ApplicationSharedMemory.java @@ -18,6 +18,7 @@ package com.android.internal.os; import android.annotation.NonNull; import android.util.Log; + import com.android.internal.annotations.VisibleForTesting; import dalvik.annotation.optimization.CriticalNative; @@ -324,4 +325,35 @@ public class ApplicationSharedMemory implements AutoCloseable { */ @FastNative private static native long nativeGetSystemNonceBlock(long ptr); + + /** + * Perform a one-time write of cached SDK feature versions. + * + * @throws IllegalStateException if the feature versions have already been written or the ashmem + * is immutable. + * @throws IllegalArgumentException if the provided feature version array is too large. + */ + public void writeSystemFeaturesCache(@NonNull int[] featureVersions) { + checkMutable(); + nativeWriteSystemFeaturesCache(mPtr, featureVersions); + } + + /** + * Read the cached SDK feature versions previously written to shared memory. + * + * Note: The result should generally be cached elsewhere for global reuse. + */ + // TODO(b/326623529): Consider using a MappedByteBuffer or equivalent to avoid needing a + // Java copy of the cached data for potentially frequent reads. Alternatively, the JNI query + // lookup for a given feature could be cheap enough to avoid the cached Java copy entirely. + public @NonNull int[] readSystemFeaturesCache() { + checkMapped(); + return nativeReadSystemFeaturesCache(mPtr); + } + + @FastNative + private static native void nativeWriteSystemFeaturesCache(long ptr, int[] cache); + + @FastNative + private static native int[] nativeReadSystemFeaturesCache(long ptr); } diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java index 2931bd2c83dd..fe616e085488 100644 --- a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java +++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java @@ -16,6 +16,7 @@ package com.android.internal.os; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import android.ravenwood.annotation.RavenwoodKeepWholeClass; @@ -155,8 +156,9 @@ public final class LongArrayMultiStateCounter implements Parcelable { /** * Adds the supplied values to the current accumulated values in the counter. + * Null `values` parameter is interpreted as an array of zeros. */ - public void incrementValues(long[] values, long timestampMs) { + public void incrementValues(@Nullable long[] values, long timestampMs) { native_incrementValues(mNativeObject, values, timestampMs); } diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java index 7030d8e84b70..4f5f37d0640e 100644 --- a/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java +++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter_ravenwood.java @@ -16,6 +16,7 @@ package com.android.internal.os; +import android.annotation.Nullable; import android.os.BadParcelableException; import android.os.Parcel; import android.ravenwood.annotation.RavenwoodKeepWholeClass; @@ -147,10 +148,12 @@ class LongArrayMultiStateCounter_ravenwood { mLastUpdateTimestampMs = timestampMs; } - public void incrementValues(long[] delta, long timestampMs) { + public void incrementValues(@Nullable long[] delta, long timestampMs) { long[] values = Arrays.copyOf(mValues, mValues.length); - for (int i = 0; i < mArrayLength; i++) { - values[i] += delta[i]; + if (delta != null) { + for (int i = 0; i < mArrayLength; i++) { + values[i] += delta[i]; + } } updateValue(values, timestampMs); } @@ -304,7 +307,8 @@ class LongArrayMultiStateCounter_ravenwood { getInstance(targetInstanceId).copyStatesFrom(getInstance(sourceInstanceId)); } - public static void native_incrementValues(long instanceId, long[] delta, long timestampMs) { + public static void native_incrementValues(long instanceId, @Nullable long[] delta, + long timestampMs) { getInstance(instanceId).incrementValues(delta, timestampMs); } diff --git a/core/java/com/android/internal/os/PowerStats.java b/core/java/com/android/internal/os/PowerStats.java index aafef6c8b5fd..6c69e2c623ad 100644 --- a/core/java/com/android/internal/os/PowerStats.java +++ b/core/java/com/android/internal/os/PowerStats.java @@ -128,6 +128,7 @@ public final class PowerStats { * Extra parameters specific to the power component, e.g. the availability of power * monitors. */ + @NonNull public final PersistableBundle extras; private PowerStatsFormatter mDeviceStatsFormatter; @@ -269,20 +270,41 @@ public final class PowerStats { stateStatsArrayLength, uidStatsArrayLength, extras); } + @SuppressWarnings("deprecation") @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Descriptor)) return false; Descriptor that = (Descriptor) o; - return powerComponentId == that.powerComponentId - && statsArrayLength == that.statsArrayLength - && stateLabels.contentEquals(that.stateLabels) - && stateStatsArrayLength == that.stateStatsArrayLength - && uidStatsArrayLength == that.uidStatsArrayLength - && Objects.equals(name, that.name) - && extras.size() == that.extras.size() // Unparcel the Parcel if not yet - && Bundle.kindofEquals(extras, - that.extras); // Since the Parcel is now unparceled, do a deep comparison + if (powerComponentId != that.powerComponentId + || statsArrayLength != that.statsArrayLength + || !stateLabels.contentEquals(that.stateLabels) + || stateStatsArrayLength != that.stateStatsArrayLength + || uidStatsArrayLength != that.uidStatsArrayLength + || !Objects.equals(name, that.name)) { + return false; + } + + // Getting the size has the side-effect of unparceling the Bundle if not yet + if (extras.size() != that.extras.size()) { + return false; + } + + if (Bundle.kindofEquals(extras, that.extras)) { + return true; + } + + // Since `kindofEquals` does not deep-compare arrays, we do that separately, albeit at + // the expense of creating an iterator and using a deprecated API, `bundle.get`. + // There is no performance concern, because the situation where PowerStatsDescriptors + // are changed in an incompatible way are exceedingly rare, occurring at most + // once per power component after a system upgrade. + for (String key : extras.keySet()) { + if (!Objects.deepEquals(extras.get(key), that.extras.get(key))) { + return false; + } + } + return true; } /** diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java index b57acf3d97fd..b19967a47001 100644 --- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java +++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java @@ -261,7 +261,12 @@ public class AconfigFlags { // Default value is false for when the flag is not found. // Note: Unlike with the old storage, with AconfigPackage, we don't have a way to // know if the flag is not found or if it's found but the value is false. - value = aconfigPackage.getBooleanFlagValue(flagName, false); + try { + value = aconfigPackage.getBooleanFlagValue(flagName, false); + } catch (Exception e) { + Slog.e(LOG_TAG, "Failed to read Aconfig flag value for " + flagPackageAndName, e); + return null; + } } if (DEBUG) { Slog.v(LOG_TAG, "Aconfig flag value for " + flagPackageAndName + " = " + value); diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java index 7ee22f30ace0..69c04807c604 100644 --- a/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java +++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java @@ -157,7 +157,7 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeString(this.name); + sForInternedString.parcel(this.name, dest, flags); dest.writeInt(this.getIcon()); dest.writeInt(this.getLabelRes()); dest.writeCharSequence(this.getNonLocalizedLabel()); @@ -175,7 +175,7 @@ public abstract class ParsedComponentImpl implements ParsedComponent, Parcelable // We use the boot classloader for all classes that we load. final ClassLoader boot = Object.class.getClassLoader(); //noinspection ConstantConditions - this.name = in.readString(); + this.name = sForInternedString.unparcel(in); this.icon = in.readInt(); this.labelRes = in.readInt(); this.nonLocalizedLabel = in.readCharSequence(); diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index d73e2d47348b..4d7709632c41 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -471,6 +471,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } /** + * This is similar to {@link #isOptingOutEdgeToEdgeEnforcement} but the caller needs to check + * whether the app declares style to opt out. + */ + public static boolean isOptOutEdgeToEdgeEnabled(ApplicationInfo info, boolean local) { + final boolean disabled = Flags.disableOptOutEdgeToEdge() + && (local + // Calling this doesn't require a permission. + ? CompatChanges.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE) + // Calling this requires permissions. + : info.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE)); + return !disabled; + } + + /** * Returns whether the given application is opting out edge-to-edge enforcement. * * @param info The application to query. @@ -480,13 +494,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { */ public static boolean isOptingOutEdgeToEdgeEnforcement(ApplicationInfo info, boolean local, TypedArray windowStyle) { - final boolean disabled = Flags.disableOptOutEdgeToEdge() - && (local - // Calling this doesn't require a permission. - ? CompatChanges.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE) - // Calling this requires permissions. - : info.isChangeEnabled(DISABLE_OPT_OUT_EDGE_TO_EDGE)); - return !disabled && windowStyle.getBoolean( + return isOptOutEdgeToEdgeEnabled(info, local) && windowStyle.getBoolean( R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false /* default */); } diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java index 93be3b02a12a..2d989943800e 100644 --- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java @@ -322,7 +322,7 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen PrintWriter pw = shell.getOutPrintWriter(); if (android.tracing.Flags.clientSideProtoLogging()) { - pw.println("Command deprecated. Please use 'cmd protolog' instead."); + pw.println("Command deprecated. Please use 'cmd protolog_configuration' instead."); return -1; } diff --git a/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java b/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java index 82d8d3431a9d..6d4a40899a65 100644 --- a/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java +++ b/core/java/com/android/internal/protolog/ProtoLogCommandHandler.java @@ -145,11 +145,11 @@ public class ProtoLogCommandHandler extends ShellCommand { switch (cmd) { case "enable" -> { - mProtoLogConfigurationService.enableProtoLogToLogcat(processGroups()); + mProtoLogConfigurationService.enableProtoLogToLogcat(pw, processGroups()); return 0; } case "disable" -> { - mProtoLogConfigurationService.disableProtoLogToLogcat(processGroups()); + mProtoLogConfigurationService.disableProtoLogToLogcat(pw, processGroups()); return 0; } default -> { diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java index d65aaae7deaa..a19690bbd0e4 100644 --- a/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java +++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationService.java @@ -18,6 +18,8 @@ package com.android.internal.protolog; import android.annotation.NonNull; +import java.io.PrintWriter; + public interface ProtoLogConfigurationService extends IProtoLogConfigurationService { /** * Get the list of groups clients have registered to the protolog service. @@ -37,11 +39,11 @@ public interface ProtoLogConfigurationService extends IProtoLogConfigurationServ * Enable logging target groups to logcat. * @param groups we want to enable logging them to logcat for. */ - void enableProtoLogToLogcat(@NonNull String... groups); + void enableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups); /** * Disable logging target groups to logcat. * @param groups we want to disable from being logged to logcat. */ - void disableProtoLogToLogcat(@NonNull String... groups); + void disableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups); } diff --git a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java index f83359dddfcc..ac1022ff1e0f 100644 --- a/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogConfigurationServiceImpl.java @@ -44,6 +44,7 @@ import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.PrintWriter; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -183,8 +184,8 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ * @param groups we want to enable logging them to logcat for. */ @Override - public void enableProtoLogToLogcat(@NonNull String... groups) { - toggleProtoLogToLogcat(true, groups); + public void enableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups) { + toggleProtoLogToLogcat(pw, true, groups); } /** @@ -192,8 +193,8 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ * @param groups we want to disable from being logged to logcat. */ @Override - public void disableProtoLogToLogcat(@NonNull String... groups) { - toggleProtoLogToLogcat(false, groups); + public void disableProtoLogToLogcat(@NonNull PrintWriter pw, @NonNull String... groups) { + toggleProtoLogToLogcat(pw, false, groups); } /** @@ -249,7 +250,9 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ } } - private void toggleProtoLogToLogcat(boolean enabled, @NonNull String[] groups) { + private void toggleProtoLogToLogcat( + @NonNull PrintWriter pw, boolean enabled, @NonNull String[] groups + ) { final var clientToGroups = new HashMap<IProtoLogClient, Set<String>>(); for (String group : groups) { @@ -257,8 +260,10 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ if (clients == null) { // No clients associated to this group - Log.w(LOG_TAG, "Attempting to toggle log to logcat for group " + group - + " with no registered clients."); + var warning = "Attempting to toggle log to logcat for group " + group + + " with no registered clients. This is a no-op."; + Log.w(LOG_TAG, warning); + pw.println("WARNING: " + warning); continue; } @@ -270,8 +275,14 @@ public class ProtoLogConfigurationServiceImpl extends IProtoLogConfigurationServ for (IProtoLogClient client : clientToGroups.keySet()) { try { - client.toggleLogcat(enabled, clientToGroups.get(client).toArray(new String[0])); + final var clientGroups = clientToGroups.get(client).toArray(new String[0]); + pw.println("Toggling logcat logging for client " + client.toString() + + " to " + enabled + " for groups: [" + + String.join(", ", clientGroups) + "]"); + client.toggleLogcat(enabled, clientGroups); + pw.println("- Done"); } catch (RemoteException e) { + pw.println("- Failed"); throw new RuntimeException( "Failed to toggle logcat status for groups on client", e); } diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java index f443b0adcb9d..c120e67dfb0d 100644 --- a/core/java/com/android/internal/util/LatencyTracker.java +++ b/core/java/com/android/internal/util/LatencyTracker.java @@ -22,6 +22,7 @@ import static android.provider.DeviceConfig.NAMESPACE_LATENCY_TRACKER; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_BACK_SYSTEM_ANIMATION; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_CHECK_CREDENTIAL_UNLOCKED; +import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FACE_WAKE_AND_UNLOCK; import static com.android.internal.util.FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_FINGERPRINT_WAKE_AND_UNLOCK; @@ -266,6 +267,15 @@ public class LatencyTracker { */ public static final int ACTION_SHADE_WINDOW_DISPLAY_CHANGE = 29; + /** + * Applicable when the user drags a full screen app's handle into the desktop drop zone to enter + * desktop mode. This measure the time from when the user releases their finger in the drop zone + * to when the animation for entering desktop mode visually begins. During this period, the + * home task and app headers for each window are initialized. Both have historically been + * expensive. See b/381396057 and b/360452034 respectively. + */ + public static final int ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG = 30; + private static final int[] ACTIONS_ALL = { ACTION_EXPAND_PANEL, ACTION_TOGGLE_RECENTS, @@ -297,6 +307,7 @@ public class LatencyTracker { ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, ACTION_SHADE_WINDOW_DISPLAY_CHANGE, + ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG, }; /** @hide */ @@ -331,10 +342,10 @@ public class LatencyTracker { ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, ACTION_SHADE_WINDOW_DISPLAY_CHANGE, + ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG, }) @Retention(RetentionPolicy.SOURCE) - public @interface Action { - } + public @interface Action {} @VisibleForTesting public static final int[] STATSD_ACTION = new int[] { @@ -368,6 +379,7 @@ public class LatencyTracker { UIACTION_LATENCY_REPORTED__ACTION__ACTION_NOTIFICATIONS_HIDDEN_FOR_MEASURE_WITH_SHADE_OPEN, UIACTION_LATENCY_REPORTED__ACTION__ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME, UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE, + UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG, }; private final Object mLock = new Object(); @@ -568,6 +580,8 @@ public class LatencyTracker { return "ACTION_KEYGUARD_FACE_UNLOCK_TO_HOME"; case UIACTION_LATENCY_REPORTED__ACTION__ACTION_SHADE_WINDOW_DISPLAY_CHANGE: return "ACTION_SHADE_WINDOW_DISPLAY_CHANGE"; + case UIACTION_LATENCY_REPORTED__ACTION__ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG: + return "ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG"; default: throw new IllegalArgumentException("Invalid action"); } diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 641ecc9b675a..ce46da12aa76 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -250,7 +250,8 @@ public class ConversationLayout extends FrameLayout mPeopleHelper.animateViewForceHidden(mImportanceRingView, forceHidden); mPeopleHelper.animateViewForceHidden(mIcon, forceHidden); }); - mConversationText = findViewById(R.id.conversation_text); + mConversationText = findViewById(notificationsRedesignTemplates() + ? R.id.title : R.id.conversation_text); mExpandButtonContainer = findViewById(R.id.expand_button_container); mExpandButtonContainerA11yContainer = findViewById(R.id.expand_button_a11y_container); @@ -716,17 +717,10 @@ public class ConversationLayout extends FrameLayout } private void updateImageMessages() { - View newMessage = null; - if (mIsCollapsed && !mGroups.isEmpty()) { - - // When collapsed, we're displaying the image message in a dedicated container - // on the right of the layout instead of inline. Let's add the isolated image there - MessagingGroup messagingGroup = mGroups.getLast(); - MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage(); - if (isolatedMessage != null) { - newMessage = isolatedMessage.getView(); - } + if (mImageMessageContainer == null) { + return; } + View newMessage = getNewImageMessage(); // Remove all messages that don't belong into the image layout View previousMessage = mImageMessageContainer.getChildAt(0); if (previousMessage != newMessage) { @@ -738,6 +732,20 @@ public class ConversationLayout extends FrameLayout mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE); } + @Nullable + private View getNewImageMessage() { + if (mIsCollapsed && !mGroups.isEmpty()) { + // When collapsed, we're displaying the image message in a dedicated container + // on the right of the layout instead of inline. Let's add the isolated image there + MessagingGroup messagingGroup = mGroups.getLast(); + MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage(); + if (isolatedMessage != null) { + return isolatedMessage.getView(); + } + } + return null; + } + public void bindFacePile(ImageView bottomBackground, ImageView bottomView, ImageView topView) { applyNotificationBackgroundColor(bottomBackground); // Let's find the two last conversations: @@ -841,6 +849,10 @@ public class ConversationLayout extends FrameLayout } private void updateAppName() { + if (notificationsRedesignTemplates()) { + return; + } + mAppName.setVisibility(mIsCollapsed ? GONE : VISIBLE); } @@ -1533,6 +1545,10 @@ public class ConversationLayout extends FrameLayout } private void updateExpandButton() { + if (notificationsRedesignTemplates()) { + return; + } + int buttonGravity; ViewGroup newContainer; if (mIsCollapsed) { @@ -1565,6 +1581,10 @@ public class ConversationLayout extends FrameLayout } private void updateContentEndPaddings() { + if (notificationsRedesignTemplates()) { + return; + } + // Let's make sure the conversation header can't run into the expand button when we're // collapsed and update the paddings of the content int headerPaddingEnd; @@ -1593,6 +1613,10 @@ public class ConversationLayout extends FrameLayout } private void onAppNameVisibilityChanged() { + if (notificationsRedesignTemplates()) { + return; + } + boolean appNameGone = mAppName.getVisibility() == GONE; if (appNameGone != mAppNameGone) { mAppNameGone = appNameGone; @@ -1601,10 +1625,18 @@ public class ConversationLayout extends FrameLayout } private void updateAppNameDividerVisibility() { + if (notificationsRedesignTemplates()) { + return; + } + mAppNameDivider.setVisibility(mAppNameGone ? GONE : VISIBLE); } public void updateExpandability(boolean expandable, @Nullable OnClickListener onClickListener) { + if (notificationsRedesignTemplates()) { + return; + } + mExpandable = expandable; if (expandable) { mExpandButtonContainer.setVisibility(VISIBLE); diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 0ec55f958f38..1f907602cb9b 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -87,10 +87,10 @@ public class LockPatternView extends View { private static final int CELL_ACTIVATE = 0; private static final int CELL_DEACTIVATE = 1; - private final int mDotSize; - private final int mDotSizeActivated; + private int mDotSize; + private int mDotSizeActivated; private final float mDotHitFactor; - private final int mPathWidth; + private int mPathWidth; private final int mLineFadeOutAnimationDurationMs; private final int mLineFadeOutAnimationDelayMs; private final int mFadePatternAnimationDurationMs; @@ -1341,6 +1341,38 @@ public class LockPatternView extends View { invalidate(); } + /** + * Change dot colors + */ + public void setDotColors(int dotColor, int dotActivatedColor) { + mDotColor = dotColor; + mDotActivatedColor = dotActivatedColor; + invalidate(); + } + + /** + * Keeps dot activated until the next dot gets activated. + */ + public void setKeepDotActivated(boolean keepDotActivated) { + mKeepDotActivated = keepDotActivated; + } + + /** + * Set dot sizes in dp + */ + public void setDotSizes(int dotSizeDp, int dotSizeActivatedDp) { + mDotSize = dotSizeDp; + mDotSizeActivated = dotSizeActivatedDp; + } + + /** + * Set the stroke width of the pattern line. + */ + public void setPathWidth(int pathWidthDp) { + mPathWidth = pathWidthDp; + mPathPaint.setStrokeWidth(mPathWidth); + } + private float getCenterXForColumn(int column) { return mPaddingLeft + column * mSquareWidth + mSquareWidth / 2f; } diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java index 31d9770f6ac4..b9a603cc5696 100644 --- a/core/java/com/android/internal/widget/MessagingGroup.java +++ b/core/java/com/android/internal/widget/MessagingGroup.java @@ -449,12 +449,8 @@ public class MessagingGroup extends NotificationOptimizedLinearLayout implements } private void updateIconVisibility() { - if (Flags.notificationsRedesignTemplates() && !mIsInConversation) { - // We don't show any icon (other than the app icon) in the collapsed form. For - // conversations, keeping this container helps with aligning the message to the icon - // when collapsed, but the old messaging style already has this alignment built into - // the template like all other layouts. Conversations are special because we use the - // same base layout for both the collapsed and expanded views. + if (Flags.notificationsRedesignTemplates()) { + // We don't show any icon (other than the app or person icon) in the collapsed form. mMessagingIconContainer.setVisibility(mSingleLine ? GONE : VISIBLE); } } diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java index e9d920ca3fcd..eb22e7c8cdc0 100644 --- a/core/java/com/android/internal/widget/MessagingLayout.java +++ b/core/java/com/android/internal/widget/MessagingLayout.java @@ -121,22 +121,38 @@ public class MessagingLayout extends FrameLayout setMessagingClippingDisabled(false); } - @RemotableViewMethod + @RemotableViewMethod(asyncImpl = "setAvatarReplacementAsync") public void setAvatarReplacement(Icon icon) { mAvatarReplacement = icon; } - @RemotableViewMethod + /** + * @hide + */ + public Runnable setAvatarReplacementAsync(Icon icon) { + mAvatarReplacement = icon; + return () -> {}; + } + + @RemotableViewMethod(asyncImpl = "setNameReplacementAsync") public void setNameReplacement(CharSequence nameReplacement) { mNameReplacement = nameReplacement; } /** + * @hide + */ + public Runnable setNameReplacementAsync(CharSequence nameReplacement) { + mNameReplacement = nameReplacement; + return () -> {}; + } + + /** * Set this layout to show the collapsed representation. * * @param isCollapsed is it collapsed */ - @RemotableViewMethod + @RemotableViewMethod(asyncImpl = "setIsCollapsedAsync") public void setIsCollapsed(boolean isCollapsed) { mIsCollapsed = isCollapsed; } @@ -145,7 +161,6 @@ public class MessagingLayout extends FrameLayout * setDataAsync needs to do different stuff for the collapsed vs expanded view, so store the * collapsed state early. */ - @RemotableViewMethod(asyncImpl = "setIsCollapsedAsync") public Runnable setIsCollapsedAsync(boolean isCollapsed) { mIsCollapsed = isCollapsed; return () -> {}; @@ -161,12 +176,20 @@ public class MessagingLayout extends FrameLayout * * @param conversationTitle the conversation title */ - @RemotableViewMethod + @RemotableViewMethod(asyncImpl = "setConversationTitleAsync") public void setConversationTitle(CharSequence conversationTitle) { mConversationTitle = conversationTitle; } /** + * @hide + */ + public Runnable setConversationTitleAsync(CharSequence conversationTitle) { + mConversationTitle = conversationTitle; + return ()->{}; + } + + /** * Set Messaging data * @param extras Bundle contains messaging data */ @@ -314,19 +337,10 @@ public class MessagingLayout extends FrameLayout } private void updateImageMessages() { - View newMessage = null; if (mImageMessageContainer == null) { return; } - if (mIsCollapsed && !mGroups.isEmpty()) { - // When collapsed, we're displaying the image message in a dedicated container - // on the right of the layout instead of inline. Let's add the isolated image there - MessagingGroup messagingGroup = mGroups.getLast(); - MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage(); - if (isolatedMessage != null) { - newMessage = isolatedMessage.getView(); - } - } + View newMessage = getNewImageMessage(); // Remove all messages that don't belong into the image layout View previousMessage = mImageMessageContainer.getChildAt(0); if (previousMessage != newMessage) { @@ -345,6 +359,20 @@ public class MessagingLayout extends FrameLayout } } + @Nullable + private View getNewImageMessage() { + if (mIsCollapsed && !mGroups.isEmpty()) { + // When collapsed, we're displaying the image message in a dedicated container + // on the right of the layout instead of inline. Let's add the isolated image there + MessagingGroup messagingGroup = mGroups.getLast(); + MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage(); + if (isolatedMessage != null) { + return isolatedMessage.getView(); + } + } + return null; + } + private void removeGroups(ArrayList<MessagingGroup> oldGroups) { int size = oldGroups.size(); for (int i = 0; i < size; i++) { @@ -417,22 +445,44 @@ public class MessagingLayout extends FrameLayout return mPeopleHelper.createAvatarSymbol(senderName, symbol, layoutColor); } - @RemotableViewMethod + @RemotableViewMethod(asyncImpl = "setLayoutColorAsync") public void setLayoutColor(int color) { mLayoutColor = color; } - @RemotableViewMethod + /** + * @hide + */ + public Runnable setLayoutColorAsync(int color) { + mLayoutColor = color; + return () -> {}; + } + + @RemotableViewMethod(asyncImpl = "setIsOneToOneAsync") public void setIsOneToOne(boolean oneToOne) { mIsOneToOne = oneToOne; } - @RemotableViewMethod + /** + * @hide + */ + public Runnable setIsOneToOneAsync(boolean oneToOne) { + mIsOneToOne = oneToOne; + return () -> {}; + } + + @RemotableViewMethod(asyncImpl = "setSenderTextColorAsync") public void setSenderTextColor(int color) { mSenderTextColor = color; } - + /** + * @hide + */ + public Runnable setSenderTextColorAsync(int color) { + mSenderTextColor = color; + return () -> {}; + } /** * @param color the color of the notification background */ @@ -441,11 +491,19 @@ public class MessagingLayout extends FrameLayout // Nothing to do with this } - @RemotableViewMethod + @RemotableViewMethod(asyncImpl = "setMessageTextColorAsync") public void setMessageTextColor(int color) { mMessageTextColor = color; } + /** + * @hide + */ + public Runnable setMessageTextColorAsync(int color) { + mMessageTextColor = color; + return () -> {}; + } + public void setUser(Person user) { mUser = user; if (mUser.getIcon() == null) { diff --git a/core/jni/android_app_PropertyInvalidatedCache.cpp b/core/jni/android_app_PropertyInvalidatedCache.cpp index 12585d5f8137..6267522f114f 100644 --- a/core/jni/android_app_PropertyInvalidatedCache.cpp +++ b/core/jni/android_app_PropertyInvalidatedCache.cpp @@ -35,7 +35,7 @@ int NonceStore::getMaxNonce() const { return kMaxNonce; } -size_t NonceStore::getMaxByte() const { +int32_t NonceStore::getMaxByte() const { return kMaxByte; } @@ -68,13 +68,13 @@ int32_t NonceStore::getHash() const { } // Copy the byte block to the target and return the current hash. -int32_t NonceStore::getByteBlock(block_t* block, size_t len) const { +int32_t NonceStore::getByteBlock(block_t* block, int32_t len) const { memcpy(block, (void*) byteBlock(), std::min(kMaxByte, len)); return mByteHash; } // Set the byte block and the hash. -void NonceStore::setByteBlock(int hash, const block_t* block, size_t len) { +void NonceStore::setByteBlock(int hash, const block_t* block, int32_t len) { memcpy((void*) byteBlock(), block, len = std::min(kMaxByte, len)); mByteHash = hash; } diff --git a/core/jni/android_app_PropertyInvalidatedCache.h b/core/jni/android_app_PropertyInvalidatedCache.h index 54a4ac65fce2..1d75182356c6 100644 --- a/core/jni/android_app_PropertyInvalidatedCache.h +++ b/core/jni/android_app_PropertyInvalidatedCache.h @@ -27,8 +27,12 @@ namespace android::app::PropertyInvalidatedCache { * location. Fields with a variable location are found via offsets. The offsets make this * object position-independent, which is required because it is in shared memory and would be * mapped into different virtual addresses for different processes. + * + * This structure is shared between 64-bit and 32-bit processes. Therefore it is imperative + * that the structure not use any datatypes that are architecture-dependent (like size_t). + * Additionally, care must be taken to avoid unexpected padding in the structure. */ -class NonceStore { +class alignas(8) NonceStore { protected: // A convenient typedef. The jbyteArray element type is jbyte, which the compiler treats as // signed char. @@ -43,23 +47,27 @@ class NonceStore { // The value of an unset field. static constexpr int UNSET = 0; - // The size of the nonce array. + // The size of the nonce array. This and the following sizes are int32_t to + // be ABI independent. const int32_t kMaxNonce; // The size of the byte array. - const size_t kMaxByte; + const int32_t kMaxByte; // The offset to the nonce array. - const size_t mNonceOffset; + const int32_t mNonceOffset; // The offset to the byte array. - const size_t mByteOffset; + const int32_t mByteOffset; // The byte block hash. This is fixed and at a known offset, so leave it in the base class. volatile std::atomic<int32_t> mByteHash; + // A 4-byte padd that makes the size of this structure a multiple of 8 bytes. + const int32_t _pad = 0; + // The constructor is protected! It only makes sense when called from a subclass. - NonceStore(int kMaxNonce, size_t kMaxByte, volatile nonce_t* nonce, volatile block_t* block) : + NonceStore(int kMaxNonce, int kMaxByte, volatile nonce_t* nonce, volatile block_t* block) : kMaxNonce(kMaxNonce), kMaxByte(kMaxByte), mNonceOffset(offset(this, const_cast<nonce_t*>(nonce))), @@ -70,7 +78,7 @@ class NonceStore { // These provide run-time access to the sizing parameters. int getMaxNonce() const; - size_t getMaxByte() const; + int getMaxByte() const; // Fetch a nonce, returning UNSET if the index is out of range. This method specifically // does not throw or generate an error if the index is out of range; this allows the method @@ -86,10 +94,10 @@ class NonceStore { int32_t getHash() const; // Copy the byte block to the target and return the current hash. - int32_t getByteBlock(block_t* block, size_t len) const; + int32_t getByteBlock(block_t* block, int32_t len) const; // Set the byte block and the hash. - void setByteBlock(int hash, const block_t* block, size_t len); + void setByteBlock(int hash, const block_t* block, int32_t len); private: @@ -113,6 +121,12 @@ class NonceStore { } }; +// Assert that the size of the object is fixed, independent of the CPU architecture. There are +// four int32_t fields and one atomic<int32_t>, which sums to 20 bytes total. This assertion +// uses a constant instead of computing the size of the objects in the compiler, to avoid +// different answers on different architectures. +static_assert(sizeof(NonceStore) == 24); + /** * A cache nonce block contains an array of std::atomic<int64_t> and an array of bytes. The * byte array has an associated hash. This class provides methods to read and write the fields @@ -126,20 +140,22 @@ class NonceStore { * The template is parameterized by the number of nonces it supports and the number of bytes in * the string block. */ -template<int maxNonce, size_t maxByte> class CacheNonce : public NonceStore { +template<int MAX_NONCE, int MAX_BYTE> class CacheNonce : public NonceStore { // The array of nonces - volatile nonce_t mNonce[maxNonce]; + volatile nonce_t mNonce[MAX_NONCE]; // The byte array. This is not atomic but it is guarded by the mByteHash. - volatile block_t mByteBlock[maxByte]; + volatile block_t mByteBlock[MAX_BYTE]; public: + // Export the parameters for use in compiler assertions. + static constexpr int kMaxNonceCount = MAX_NONCE; + static constexpr int kMaxByteCount = MAX_BYTE; + // Construct and initialize the memory. - CacheNonce() : - NonceStore(maxNonce, maxByte, &mNonce[0], &mByteBlock[0]) - { - for (int i = 0; i < maxNonce; i++) { + CacheNonce() : NonceStore(MAX_NONCE, MAX_BYTE, &mNonce[0], &mByteBlock[0]) { + for (int i = 0; i < MAX_NONCE; i++) { mNonce[i] = UNSET; } mByteHash = UNSET; @@ -155,4 +171,10 @@ template<int maxNonce, size_t maxByte> class CacheNonce : public NonceStore { typedef CacheNonce</* max nonce */ 128, /* byte block size */ 8192> SystemCacheNonce; // LINT.ThenChange(/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java:system_nonce_config) +// Verify that there is no padding in the final class. +static_assert(sizeof(SystemCacheNonce) == + sizeof(NonceStore) + + SystemCacheNonce::kMaxNonceCount*8 + + SystemCacheNonce::kMaxByteCount); + } // namespace android.app.PropertyInvalidatedCache diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 2ba6bc4912c3..b679688959b1 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -664,14 +664,16 @@ static void android_media_AudioSystem_vol_range_init_req_callback() static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint state, jobject jParcel, - jint codec) { + jint codec, jboolean deviceSwitch) { int status; if (Parcel *parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) { android::media::audio::common::AudioPort port{}; if (status_t statusOfParcel = port.readFromParcel(parcel); statusOfParcel == OK) { - status = check_AudioSystem_Command( - AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(state), - port, static_cast<audio_format_t>(codec))); + status = check_AudioSystem_Command( + AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>( + state), + port, static_cast<audio_format_t>(codec), + deviceSwitch)); } else { ALOGE("Failed to read from parcel: %s", statusToString(statusOfParcel).c_str()); status = kAudioStatusError; @@ -3457,7 +3459,7 @@ static const JNINativeMethod gMethods[] = { MAKE_AUDIO_SYSTEM_METHOD(newAudioSessionId), MAKE_AUDIO_SYSTEM_METHOD(newAudioPlayerId), MAKE_AUDIO_SYSTEM_METHOD(newAudioRecorderId), - MAKE_JNI_NATIVE_METHOD("setDeviceConnectionState", "(ILandroid/os/Parcel;I)I", + MAKE_JNI_NATIVE_METHOD("setDeviceConnectionState", "(ILandroid/os/Parcel;IZ)I", android_media_AudioSystem_setDeviceConnectionState), MAKE_AUDIO_SYSTEM_METHOD(getDeviceConnectionState), MAKE_AUDIO_SYSTEM_METHOD(handleDeviceConfigChange), diff --git a/core/jni/android_os_PerfettoTrackEventExtra.cpp b/core/jni/android_os_PerfettoTrackEventExtra.cpp index b8bdc8c29199..18f05cabd12d 100644 --- a/core/jni/android_os_PerfettoTrackEventExtra.cpp +++ b/core/jni/android_os_PerfettoTrackEventExtra.cpp @@ -23,7 +23,8 @@ #include <nativehelper/utils.h> #include <tracing_sdk.h> -static constexpr ssize_t kMaxStrLen = 4096; +#include <list> + namespace android { template <typename T> inline static T* toPointer(jlong ptr) { @@ -35,24 +36,145 @@ inline static jlong toJLong(T* ptr) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr)); } +/** + * @brief A thread-safe utility class for converting Java UTF-16 strings to ASCII in JNI + * environment. + * + * StringBuffer provides efficient conversion of Java strings to ASCII with optimized memory + * handling. + * It uses a two-tiered buffering strategy: + * 1. A fast path using pre-allocated thread-local buffers for strings up to 128 characters + * 2. A fallback path using dynamic allocation for longer strings + * + * Non-ASCII characters (>255) are replaced with '?' during conversion. The class maintains + * thread safety through thread-local storage and provides zero-copy string views for optimal + * performance. + * + * Memory Management: + * - Uses fixed-size thread-local buffers for both UTF-16 and ASCII characters + * - Overflow strings are stored in a thread-local list to maintain valid string views + * - Avoids unnecessary allocations in the common case of small strings + * + * Usage example: + * @code + * JNIEnv* env = ...; + * jstring java_string = ...; + * std::string_view ascii = StringBuffer::utf16_to_ascii(env, java_string); + * // Use the ASCII string... + * StringBuffer::reset(); // Clean up when done + * @endcode + * + * Thread Safety: All methods are thread-safe due to thread-local storage. + */ +class StringBuffer { +private: + static constexpr size_t BASE_SIZE = 128; + // Temporarily stores the UTF-16 characters retrieved from the Java + // string before they are converted to ASCII. + static thread_local inline char char_buffer[BASE_SIZE]; + // For fast-path conversions when the resulting ASCII string fits within + // the pre-allocated space. All ascii strings in a trace event will be stored + // here until emitted. + static thread_local inline jchar jchar_buffer[BASE_SIZE]; + // When the fast-path conversion is not possible (because char_buffer + // doesn't have enough space), the converted ASCII string is stored + // in this list. We use list here to avoid moving the strings on resize + // with vector. This way, we can give out string_views from the stored strings. + // The additional overhead from list node allocations is fine cos we are already + // in an extremely unlikely path here and there are other bigger problems if here. + static thread_local inline std::list<std::string> overflow_strings; + // current offset into the char_buffer. + static thread_local inline size_t current_offset{0}; + // This allows us avoid touching the overflow_strings directly in the fast path. + // Touching it causes some thread local init routine to run which shows up in profiles. + static thread_local inline bool is_overflow_strings_empty = true; + + static void copy_utf16_to_ascii(const jchar* src, size_t len, char* dst, JNIEnv* env, + jstring str) { + std::transform(src, src + len, dst, + [](jchar c) { return (c <= 0xFF) ? static_cast<char>(c) : '?'; }); + + if (src != jchar_buffer) { + // We hit the slow path to populate src, so we have to release. + env->ReleaseStringCritical(str, src); + } + } + +public: + static void reset() { + if (!is_overflow_strings_empty) { + overflow_strings.clear(); + is_overflow_strings_empty = true; + } + current_offset = 0; + } + + // Converts a Java string (jstring) to an ASCII string_view. Characters + // outside the ASCII range (0-255) are replaced with '?'. + // + // @param env The JNI environment. + // @param val The Java string to convert. + // @return A string_view representing the ASCII version of the string. + // Returns an empty string_view if the input is null or empty. + static std::string_view utf16_to_ascii(JNIEnv* env, jstring val) { + if (!val) return ""; + + const jsize len = env->GetStringLength(val); + if (len == 0) return ""; + + const jchar* temp_buffer; + + // Fast path: Enough space in jchar_buffer + if (static_cast<size_t>(len) <= BASE_SIZE) { + env->GetStringRegion(val, 0, len, jchar_buffer); + temp_buffer = jchar_buffer; + } else { + // Slow path: Fallback to asking ART for the string which will likely + // allocate and return a copy. + temp_buffer = env->GetStringCritical(val, nullptr); + } + + const size_t next_offset = current_offset + len + 1; + // Fast path: Enough space in char_buffer + if (BASE_SIZE > next_offset) { + const size_t start_offset = current_offset; + + copy_utf16_to_ascii(temp_buffer, len, char_buffer + current_offset, env, val); + char_buffer[current_offset + len] = '\0'; + + auto res = std::string_view(char_buffer + current_offset, len); + current_offset = next_offset; + return res; + } else { + // Slow path: Not enough space in char_buffer. Use overflow_strings. + // This will cause a string alloc but should be very unlikely to hit. + std::string& str = overflow_strings.emplace_back(len + 1, '\0'); + + copy_utf16_to_ascii(temp_buffer, len, str.data(), env, val); + is_overflow_strings_empty = false; + return std::string_view(str); + } + } +}; + static jlong android_os_PerfettoTrackEventExtraArgInt64_init(JNIEnv* env, jclass, jstring name) { - ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name); - return toJLong(new tracing_perfetto::DebugArg<int64_t>(name_chars.c_str())); + return toJLong(new tracing_perfetto::DebugArg<int64_t>( + StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraArgBool_init(JNIEnv* env, jclass, jstring name) { - ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name); - return toJLong(new tracing_perfetto::DebugArg<bool>(name_chars.c_str())); + return toJLong( + new tracing_perfetto::DebugArg<bool>(StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraArgDouble_init(JNIEnv* env, jclass, jstring name) { - ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name); - return toJLong(new tracing_perfetto::DebugArg<double>(name_chars.c_str())); + return toJLong( + new tracing_perfetto::DebugArg<double>(StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraArgString_init(JNIEnv* env, jclass, jstring name) { - ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name); - return toJLong(new tracing_perfetto::DebugArg<const char*>(name_chars.c_str())); + return toJLong(new tracing_perfetto::DebugArg<const char*>( + StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraArgInt64_delete() { @@ -109,11 +231,9 @@ static void android_os_PerfettoTrackEventExtraArgDouble_set_value(jlong ptr, jdo static void android_os_PerfettoTrackEventExtraArgString_set_value(JNIEnv* env, jclass, jlong ptr, jstring val) { - ScopedUtfChars val_chars = GET_UTF_OR_RETURN_VOID(env, val); - tracing_perfetto::DebugArg<const char*>* arg = toPointer<tracing_perfetto::DebugArg<const char*>>(ptr); - arg->set_value(strdup(val_chars.c_str())); + arg->set_value(StringBuffer::utf16_to_ascii(env, val).data()); } static jlong android_os_PerfettoTrackEventExtraFieldInt64_init() { @@ -186,11 +306,9 @@ static void android_os_PerfettoTrackEventExtraFieldDouble_set_value(jlong ptr, j static void android_os_PerfettoTrackEventExtraFieldString_set_value(JNIEnv* env, jclass, jlong ptr, jlong id, jstring val) { - ScopedUtfChars val_chars = GET_UTF_OR_RETURN_VOID(env, val); - tracing_perfetto::ProtoField<const char*>* field = toPointer<tracing_perfetto::ProtoField<const char*>>(ptr); - field->set_value(id, strdup(val_chars.c_str())); + field->set_value(id, StringBuffer::utf16_to_ascii(env, val).data()); } static void android_os_PerfettoTrackEventExtraFieldNested_add_field(jlong field_ptr, @@ -231,8 +349,9 @@ static jlong android_os_PerfettoTrackEventExtraFlow_get_extra_ptr(jlong ptr) { static jlong android_os_PerfettoTrackEventExtraNamedTrack_init(JNIEnv* env, jclass, jlong id, jstring name, jlong parent_uuid) { - ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name); - return toJLong(new tracing_perfetto::NamedTrack(id, parent_uuid, name_chars.c_str())); + return toJLong( + new tracing_perfetto::NamedTrack(id, parent_uuid, + StringBuffer::utf16_to_ascii(env, name).data())); } static jlong android_os_PerfettoTrackEventExtraNamedTrack_delete() { @@ -246,9 +365,10 @@ static jlong android_os_PerfettoTrackEventExtraNamedTrack_get_extra_ptr(jlong pt static jlong android_os_PerfettoTrackEventExtraCounterTrack_init(JNIEnv* env, jclass, jstring name, jlong parent_uuid) { - ScopedUtfChars name_chars = GET_UTF_OR_RETURN(env, name); - - return toJLong(new tracing_perfetto::RegisteredTrack(1, parent_uuid, name_chars.c_str(), true)); + return toJLong( + new tracing_perfetto::RegisteredTrack(1, parent_uuid, + StringBuffer::utf16_to_ascii(env, name).data(), + true)); } static jlong android_os_PerfettoTrackEventExtraCounterTrack_delete() { @@ -318,11 +438,11 @@ static void android_os_PerfettoTrackEventExtra_clear_args(jlong ptr) { static void android_os_PerfettoTrackEventExtra_emit(JNIEnv* env, jclass, jint type, jlong cat_ptr, jstring name, jlong extra_ptr) { - ScopedUtfChars name_chars = GET_UTF_OR_RETURN_VOID(env, name); - tracing_perfetto::Category* category = toPointer<tracing_perfetto::Category>(cat_ptr); - tracing_perfetto::trace_event(type, category->get(), name_chars.c_str(), + tracing_perfetto::trace_event(type, category->get(), + StringBuffer::utf16_to_ascii(env, name).data(), toPointer<tracing_perfetto::Extra>(extra_ptr)); + StringBuffer::reset(); } static jlong android_os_PerfettoTrackEventExtraProto_init() { diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index b2649a471b8a..a73ff421acf7 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -424,6 +424,15 @@ static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin assetmanager->SetDefaultLocale(default_locale_int); } +static void NativeSetOverlayConstraints(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, + jint displayId, jint deviceId) { + ATRACE_NAME("AssetManager::SetDisplayIdAndDeviceId"); + + auto assetmanager = LockAndStartAssetManager(ptr); + assetmanager->SetOverlayConstraints(static_cast<int32_t>(displayId), + static_cast<int32_t>(deviceId)); +} + static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr, jboolean includeOverlays, jboolean includeLoaders) { @@ -1554,6 +1563,7 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;ZZ)V", (void*)NativeSetApkAssets}, {"nativeSetConfiguration", "(JIILjava/lang/String;[Ljava/lang/String;IIIIIIIIIIIIIIIIZ)V", (void*)NativeSetConfiguration}, + {"nativeSetOverlayConstraints", "(JII)V", (void*)NativeSetOverlayConstraints}, {"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;", (void*)NativeGetAssignedPackageIdentifiers}, diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index b99b0ef7f24e..a8e51a7c1fe8 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -765,28 +765,28 @@ static void nativeSetLuts(JNIEnv* env, jclass clazz, jlong transactionObj, jlong std::vector<int32_t> dimensions; std::vector<int32_t> sizes; std::vector<int32_t> samplingKeys; - int32_t fd = -1; + base::unique_fd fd; if (jdimensionArray) { jsize numLuts = env->GetArrayLength(jdimensionArray); - ScopedIntArrayRW joffsets(env, joffsetArray); + ScopedIntArrayRO joffsets(env, joffsetArray); if (joffsets.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray"); + jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRO from joffsetArray"); return; } - ScopedIntArrayRW jdimensions(env, jdimensionArray); + ScopedIntArrayRO jdimensions(env, jdimensionArray); if (jdimensions.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray"); + jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRO from jdimensionArray"); return; } - ScopedIntArrayRW jsizes(env, jsizeArray); + ScopedIntArrayRO jsizes(env, jsizeArray); if (jsizes.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray"); + jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRO from jsizeArray"); return; } - ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray); + ScopedIntArrayRO jsamplingKeys(env, jsamplingKeyArray); if (jsamplingKeys.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray"); + jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRO from jsamplingKeyArray"); return; } @@ -796,15 +796,15 @@ static void nativeSetLuts(JNIEnv* env, jclass clazz, jlong transactionObj, jlong sizes = std::vector<int32_t>(jsizes.get(), jsizes.get() + numLuts); samplingKeys = std::vector<int32_t>(jsamplingKeys.get(), jsamplingKeys.get() + numLuts); - ScopedFloatArrayRW jbuffers(env, jbufferArray); + ScopedFloatArrayRO jbuffers(env, jbufferArray); if (jbuffers.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray"); + jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRO from jbufferArray"); return; } // create the shared memory and copy jbuffers size_t bufferSize = jbuffers.size() * sizeof(float); - fd = ashmem_create_region("lut_shared_mem", bufferSize); + fd.reset(ashmem_create_region("lut_shared_mem", bufferSize)); if (fd < 0) { jniThrowRuntimeException(env, "ashmem_create_region() failed"); return; @@ -820,7 +820,7 @@ static void nativeSetLuts(JNIEnv* env, jclass clazz, jlong transactionObj, jlong } } - transaction->setLuts(ctrl, base::unique_fd(fd), offsets, dimensions, sizes, samplingKeys); + transaction->setLuts(ctrl, std::move(fd), offsets, dimensions, sizes, samplingKeys); } static void nativeSetPictureProfileId(JNIEnv* env, jclass clazz, jlong transactionObj, diff --git a/core/jni/com_android_internal_os_ApplicationSharedMemory.cpp b/core/jni/com_android_internal_os_ApplicationSharedMemory.cpp index cc1687cd9ffb..71d169419cd3 100644 --- a/core/jni/com_android_internal_os_ApplicationSharedMemory.cpp +++ b/core/jni/com_android_internal_os_ApplicationSharedMemory.cpp @@ -23,18 +23,67 @@ #include <string.h> #include <sys/mman.h> +#include <array> #include <atomic> #include <cstddef> #include <new> -#include "core_jni_helpers.h" - #include "android_app_PropertyInvalidatedCache.h" +#include "core_jni_helpers.h" namespace { using namespace android::app::PropertyInvalidatedCache; +class alignas(8) SystemFeaturesCache { +public: + // We only need enough space to handle the official set of SDK-defined system features (~200). + // TODO(b/326623529): Reuse the exact value defined by PackageManager.SDK_FEATURE_COUNT. + static constexpr int32_t kMaxSystemFeatures = 512; + + void writeSystemFeatures(JNIEnv* env, jintArray jfeatures) { + if (featuresLength.load(std::memory_order_seq_cst) > 0) { + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "SystemFeaturesCache already written."); + return; + } + + int32_t jfeaturesLength = env->GetArrayLength(jfeatures); + if (jfeaturesLength > kMaxSystemFeatures) { + jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", + "SystemFeaturesCache only supports %d elements (vs %d requested).", + kMaxSystemFeatures, jfeaturesLength); + return; + } + env->GetIntArrayRegion(jfeatures, 0, jfeaturesLength, features.data()); + featuresLength.store(jfeaturesLength, std::memory_order_seq_cst); + } + + jintArray readSystemFeatures(JNIEnv* env) const { + jint jfeaturesLength = static_cast<jint>(featuresLength.load(std::memory_order_seq_cst)); + jintArray jfeatures = env->NewIntArray(jfeaturesLength); + if (env->ExceptionCheck()) { + return nullptr; + } + + env->SetIntArrayRegion(jfeatures, 0, jfeaturesLength, features.data()); + return jfeatures; + } + +private: + // A fixed length array of feature versions, with |featuresLength| dictating the actual size + // of features that have been written. + std::array<int32_t, kMaxSystemFeatures> features = {}; + // The atomic acts as a barrier that precedes reads and follows writes, ensuring a + // consistent view of |features| across processes. Note that r/w synchronization *within* a + // process is handled at a higher level. + std::atomic<int64_t> featuresLength = 0; +}; + +static_assert(sizeof(SystemFeaturesCache) == + sizeof(int32_t) * SystemFeaturesCache::kMaxSystemFeatures + sizeof(int64_t), + "Unexpected SystemFeaturesCache size"); + // Atomics should be safe to use across processes if they are lock free. static_assert(std::atomic<int64_t>::is_always_lock_free == true, "atomic<int64_t> is not always lock free"); @@ -69,14 +118,25 @@ public: latestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis = offset; } + // The fixed size cache storage for SDK-defined system features. + SystemFeaturesCache systemFeaturesCache; + // The nonce storage for pic. The sizing is suitable for the system server module. SystemCacheNonce systemPic; }; -// Update the expected value when modifying the members of SharedMemory. +// Update the expected values when modifying the members of SharedMemory. // The goal of this assertion is to ensure that the data structure is the same size across 32-bit // and 64-bit systems. -static_assert(sizeof(SharedMemory) == 8 + sizeof(SystemCacheNonce), "Unexpected SharedMemory size"); +// TODO(b/396674280): Add an additional fixed size check for SystemCacheNonce after resolving +// ABI discrepancies. +static_assert(sizeof(SharedMemory) == 8 + sizeof(SystemFeaturesCache) + sizeof(SystemCacheNonce), + "Unexpected SharedMemory size"); +static_assert(offsetof(SharedMemory, systemFeaturesCache) == sizeof(int64_t), + "Unexpected SystemFeaturesCache offset in SharedMemory"); +static_assert(offsetof(SharedMemory, systemPic) == + offsetof(SharedMemory, systemFeaturesCache) + sizeof(SystemFeaturesCache), + "Unexpected SystemCachceNonce offset in SharedMemory"); static jint nativeCreate(JNIEnv* env, jclass) { // Create anonymous shared memory region @@ -146,6 +206,16 @@ static jlong nativeGetSystemNonceBlock(JNIEnv*, jclass*, jlong ptr) { return reinterpret_cast<jlong>(&sharedMemory->systemPic); } +static void nativeWriteSystemFeaturesCache(JNIEnv* env, jclass*, jlong ptr, jintArray jfeatures) { + SharedMemory* sharedMemory = reinterpret_cast<SharedMemory*>(ptr); + sharedMemory->systemFeaturesCache.writeSystemFeatures(env, jfeatures); +} + +static jintArray nativeReadSystemFeaturesCache(JNIEnv* env, jclass*, jlong ptr) { + SharedMemory* sharedMemory = reinterpret_cast<SharedMemory*>(ptr); + return sharedMemory->systemFeaturesCache.readSystemFeatures(env); +} + static const JNINativeMethod gMethods[] = { {"nativeCreate", "()I", (void*)nativeCreate}, {"nativeMap", "(IZ)J", (void*)nativeMap}, @@ -156,7 +226,9 @@ static const JNINativeMethod gMethods[] = { (void*)nativeSetLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis}, {"nativeGetLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis", "(J)J", (void*)nativeGetLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis}, - {"nativeGetSystemNonceBlock", "(J)J", (void*) nativeGetSystemNonceBlock}, + {"nativeGetSystemNonceBlock", "(J)J", (void*)nativeGetSystemNonceBlock}, + {"nativeWriteSystemFeaturesCache", "(J[I)V", (void*)nativeWriteSystemFeaturesCache}, + {"nativeReadSystemFeaturesCache", "(J)[I", (void*)nativeReadSystemFeaturesCache}, }; static const char kApplicationSharedMemoryClassName[] = diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp index 7ffe0ed7c6cd..8f36ecb8b01a 100644 --- a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp +++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp @@ -97,7 +97,13 @@ static void native_updateValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray static void native_incrementValues(JNIEnv *env, jclass, jlong nativePtr, jlongArray values, jlong timestamp) { auto *counter = reinterpret_cast<LongArrayMultiStateCounter *>(nativePtr); - counter->incrementValue(JavaUint64Array(env, values), timestamp); + if (values != nullptr) { + counter->incrementValue(JavaUint64Array(env, values), timestamp); + } else { + // Pass an empty Uint64Array, which is equivalent to an array of zeros. + // This is done to ensure that the timestamp is still updated in the counter. + counter->incrementValue(Uint64Array(), timestamp); + } } static void native_addCounts(JNIEnv *env, jclass, jlong nativePtr, jlongArray values) { diff --git a/core/proto/OWNERS b/core/proto/OWNERS index b51f72dee260..aa8f8419ac46 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -5,7 +5,6 @@ joeo@google.com singhtejinder@google.com yanmin@google.com yaochen@google.com -yro@google.com zhouwenjie@google.com # Frameworks diff --git a/core/proto/android/providers/settings/common.proto b/core/proto/android/providers/settings/common.proto index 64ffefb695a6..931192e7f1e7 100644 --- a/core/proto/android/providers/settings/common.proto +++ b/core/proto/android/providers/settings/common.proto @@ -37,6 +37,9 @@ message SettingProto { // Whether the default is set by the system optional bool default_from_system = 6; + + // Whether the value is ignored when restoring from backup + optional bool preserved_in_restore = 7; } message SettingsOperationProto { diff --git a/packages/CtsShim/build/shim/AndroidManifestUpgrade.xml b/core/res/res/drawable/accessibility_autoclick_resume.xml index 7f3644a18ad6..ae83e9805cc9 100644 --- a/packages/CtsShim/build/shim/AndroidManifestUpgrade.xml +++ b/core/res/res/drawable/accessibility_autoclick_resume.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2016 The Android Open Source Project + +<!-- Copyright 2025 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,17 +15,15 @@ limitations under the License. --> -<!-- Manifest for the system CTS shim --> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - package="com.android.cts.ctsshim" > - - <uses-sdk - android:minSdkVersion="24" - android:targetSdkVersion="28" /> - - <application - android:hasCode="false" - tools:ignore="AllowBackup,MissingApplicationIcon" /> -</manifest> - +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:viewportWidth="24" + android:viewportHeight="24" + android:width="24dp" + android:height="24dp"> + <group> + <clip-path android:pathData="M0 0H24V24H0V0Z" /> + <path + android:pathData="M8 19V5L19 12L8 19Z" + android:fillColor="@color/materialColorPrimary" /> + </group> +</vector> diff --git a/core/res/res/drawable/progress_ring_watch.xml b/core/res/res/drawable/progress_ring_watch.xml index 8250ee600a8f..2e65ff13b3de 100644 --- a/core/res/res/drawable/progress_ring_watch.xml +++ b/core/res/res/drawable/progress_ring_watch.xml @@ -16,27 +16,27 @@ --> <rotate xmlns:android="http://schemas.android.com/apk/res/android" - android:fromDegrees = "270" - android:toDegrees="270" - android:pivotX="50%" - android:pivotY="50%" > + android:fromDegrees="270" + android:toDegrees="270"> <layer-list> <item> <shape - android:shape="ring" - android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio" + android:shape="arc" + android:useLevel="false" android:thickness="@dimen/progressbar_thickness" - android:useLevel="false"> - <solid android:color="@color/materialColorSurfaceContainer"/> + android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio" + android:strokeCap="round"> + <solid android:color="@*android:color/materialColorSurfaceContainer"/> </shape> </item> <item> <shape - android:shape="ring" - android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio" + android:shape="arc" + android:useLevel="true" android:thickness="@dimen/progressbar_thickness" - android:useLevel="true"> - <solid android:color="@color/materialColorPrimary"/> + android:innerRadiusRatio="@dimen/progressbar_inner_radius_ratio" + android:strokeCap="round"> + <solid android:color="@*android:color/materialColorPrimary"/> </shape> </item> </layer-list> diff --git a/core/res/res/layout/media_route_controller_dialog.xml b/core/res/res/layout/media_route_controller_dialog.xml index 24a25353f40d..a5cd83be9f6c 100644 --- a/core/res/res/layout/media_route_controller_dialog.xml +++ b/core/res/res/layout/media_route_controller_dialog.xml @@ -41,11 +41,5 @@ android:layout_marginLeft="8dp" android:layout_marginRight="8dp" /> </LinearLayout> - - <!-- Optional content view section. --> - <FrameLayout android:id="@+id/media_route_control_frame" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:visibility="gone" /> </LinearLayout> </ScrollView> diff --git a/core/res/res/layout/notification_2025_conversation_header.xml b/core/res/res/layout/notification_2025_conversation_header.xml index 75bd244cbbf4..68096f8cc50e 100644 --- a/core/res/res/layout/notification_2025_conversation_header.xml +++ b/core/res/res/layout/notification_2025_conversation_header.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2024 The Android Open Source Project + ~ Copyright (C) 2025 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. @@ -15,157 +15,74 @@ ~ limitations under the License --> -<com.android.internal.widget.ConversationHeaderLinearLayout +<!-- extends RelativeLayout --> +<NotificationHeaderView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/conversation_header" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:id="@+id/notification_header" + android:layout_width="match_parent" + android:layout_height="@dimen/notification_2025_header_height" + android:clipChildren="false" + android:gravity="center_vertical" android:orientation="horizontal" - android:paddingTop="@dimen/notification_2025_margin" + android:theme="@style/Theme.DeviceDefault.Notification" + android:importantForAccessibility="no" > - <TextView - android:id="@+id/conversation_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" - android:textSize="@dimen/notification_2025_title_text_size" - android:singleLine="true" - android:layout_weight="1" - /> - - <TextView - android:id="@+id/app_name_divider" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:text="@string/notification_header_divider_symbol" - android:singleLine="true" + <ImageView + android:id="@+id/left_icon" + android:layout_width="@dimen/notification_2025_left_icon_size" + android:layout_height="@dimen/notification_2025_left_icon_size" + android:layout_alignParentStart="true" + android:layout_margin="@dimen/notification_2025_margin" + android:background="@drawable/notification_large_icon_outline" + android:clipToOutline="true" + android:importantForAccessibility="no" + android:scaleType="centerCrop" android:visibility="gone" /> - <!-- App Name --> - <com.android.internal.widget.ObservableTextView - android:id="@+id/app_name_text" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:singleLine="true" - android:visibility="gone" - /> + <include layout="@layout/notification_2025_conversation_icon_container" /> - <TextView - android:id="@+id/time_divider" + <!-- extends ViewGroup --> + <NotificationTopLineView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/notification_top_line" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:text="@string/notification_header_divider_symbol" - android:singleLine="true" - android:visibility="gone" - /> + android:layout_alignParentStart="true" + android:layout_toStartOf="@id/expand_button" + android:layout_alignWithParentIfMissing="true" + android:layout_marginVertical="@dimen/notification_2025_margin" + android:clipChildren="false" + android:gravity="center_vertical" + android:paddingStart="@dimen/notification_2025_content_margin_start" + android:theme="@style/Theme.DeviceDefault.Notification" + > - <DateTimeView - android:id="@+id/time" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:showRelative="true" - android:singleLine="true" - android:visibility="gone" - /> + <include layout="@layout/notification_2025_top_line_views" /> - <ViewStub - android:id="@+id/chronometer" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:layout="@layout/notification_template_part_chronometer" - android:visibility="gone" - /> + </NotificationTopLineView> - <TextView - android:id="@+id/verification_divider" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:text="@string/notification_header_divider_symbol" - android:singleLine="true" - android:visibility="gone" - /> - - <ImageView - android:id="@+id/verification_icon" - android:layout_width="@dimen/notification_verification_icon_size" - android:layout_height="@dimen/notification_verification_icon_size" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:baseline="10dp" - android:scaleType="fitCenter" - android:src="@drawable/ic_notifications_alerted" - android:visibility="gone" + <FrameLayout + android:id="@+id/alternate_expand_target" + android:layout_width="@dimen/notification_2025_content_margin_start" + android:layout_height="match_parent" + android:layout_alignParentStart="true" + android:importantForAccessibility="no" + android:focusable="false" /> - <TextView - android:id="@+id/verification_text" - android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + <include layout="@layout/notification_2025_expand_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:layout_weight="100" - android:showRelative="true" - android:singleLine="true" - android:visibility="gone" - /> + android:layout_gravity="top|end" + android:layout_alignParentEnd="true" /> - <ImageButton - android:id="@+id/feedback" - android:layout_width="@dimen/notification_feedback_size" - android:layout_height="@dimen/notification_feedback_size" - android:layout_marginStart="@dimen/notification_header_separating_margin" - android:background="?android:selectableItemBackgroundBorderless" - android:contentDescription="@string/notification_feedback_indicator" - android:baseline="13dp" - android:scaleType="fitCenter" - android:src="@drawable/ic_feedback_indicator" - android:visibility="gone" - /> + <include layout="@layout/notification_close_button" + android:id="@+id/close_button" + android:layout_width="@dimen/notification_close_button_size" + android:layout_height="@dimen/notification_close_button_size" + android:layout_alignParentTop="true" + android:layout_alignParentEnd="true" /> - <ImageView - android:id="@+id/phishing_alert" - android:layout_width="@dimen/notification_2025_badge_size" - android:layout_height="@dimen/notification_2025_badge_size" - android:layout_marginStart="@dimen/notification_2025_badge_margin" - android:baseline="@dimen/notification_2025_badge_baseline" - android:scaleType="fitCenter" - android:src="@drawable/ic_dialog_alert_material" - android:visibility="gone" - android:contentDescription="@string/notification_phishing_alert_content_description" - /> - - <ImageView - android:id="@+id/profile_badge" - android:layout_width="@dimen/notification_2025_badge_size" - android:layout_height="@dimen/notification_2025_badge_size" - android:layout_marginStart="@dimen/notification_2025_badge_margin" - android:baseline="@dimen/notification_2025_badge_baseline" - android:scaleType="fitCenter" - android:visibility="gone" - android:contentDescription="@string/notification_work_profile_content_description" - /> - - <ImageView - android:id="@+id/alerted_icon" - android:layout_width="@dimen/notification_2025_badge_size" - android:layout_height="@dimen/notification_2025_badge_size" - android:layout_marginStart="@dimen/notification_2025_badge_margin" - android:baseline="@dimen/notification_2025_badge_baseline" - android:contentDescription="@string/notification_alerted_content_description" - android:scaleType="fitCenter" - android:src="@drawable/ic_notifications_alerted" - android:visibility="gone" - /> -</com.android.internal.widget.ConversationHeaderLinearLayout> +</NotificationHeaderView> diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml index 054583297d37..d29b7af9e24e 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_base.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml @@ -102,7 +102,6 @@ android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" - android:textSize="@dimen/notification_2025_title_text_size" /> <include layout="@layout/notification_2025_top_line_views" /> diff --git a/core/res/res/layout/notification_2025_template_collapsed_call.xml b/core/res/res/layout/notification_2025_template_collapsed_call.xml index 6f3c15adb082..f1729b3c2f76 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_call.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_call.xml @@ -47,7 +47,7 @@ > <include - layout="@layout/notification_2025_conversation_header" + layout="@layout/notification_template_conversation_header" android:layout_width="wrap_content" android:layout_height="wrap_content" /> diff --git a/core/res/res/layout/notification_2025_template_collapsed_conversation.xml b/core/res/res/layout/notification_2025_template_collapsed_conversation.xml new file mode 100644 index 000000000000..f80411103501 --- /dev/null +++ b/core/res/res/layout/notification_2025_template_collapsed_conversation.xml @@ -0,0 +1,216 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<!-- extends FrameLayout --> +<com.android.internal.widget.ConversationLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/status_bar_latest_event_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipChildren="false" + android:tag="conversation" + > + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipChildren="false" + android:orientation="vertical" + > + + + <com.android.internal.widget.NotificationMaxHeightFrameLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="@dimen/notification_2025_min_height" + android:clipChildren="false" + > + + <ImageView + android:id="@+id/left_icon" + android:layout_width="@dimen/notification_2025_left_icon_size" + android:layout_height="@dimen/notification_2025_left_icon_size" + android:layout_alignParentStart="true" + android:layout_margin="@dimen/notification_2025_margin" + android:background="@drawable/notification_large_icon_outline" + android:clipToOutline="true" + android:importantForAccessibility="no" + android:scaleType="centerCrop" + android:visibility="gone" + /> + + <include layout="@layout/notification_2025_conversation_icon_container" /> + + <FrameLayout + android:id="@+id/alternate_expand_target" + android:layout_width="@dimen/notification_2025_content_margin_start" + android:layout_height="match_parent" + android:layout_gravity="start" + android:importantForAccessibility="no" + android:focusable="false" + /> + + <!-- + NOTE: to make the expansion animation of id/notification_messaging happen vertically, + its X positioning must be the left edge of the notification, so instead of putting the + layout_marginStart on the id/notification_headerless_view_row, we put it on + id/notification_top_line, making the layout here just a bit different from the base. + --> + <LinearLayout + android:id="@+id/notification_headerless_view_row" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:clipChildren="false" + > + + <!-- + NOTE: because messaging will always have 2 lines, this LinearLayout should NOT + have the id/notification_headerless_view_column, as that is used for modifying + vertical margins to accommodate the single-line state that base supports + --> + <LinearLayout + android:layout_width="0px" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:layout_marginBottom="@dimen/notification_2025_margin" + android:layout_marginTop="@dimen/notification_2025_margin" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" + android:clipChildren="false" + android:orientation="vertical" + > + + <NotificationTopLineView + android:id="@+id/notification_top_line" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/notification_headerless_line_height" + android:clipChildren="false" + android:theme="@style/Theme.DeviceDefault.Notification" + > + + <!-- + NOTE: The notification_2025_top_line_views layout contains the app_name_text. + In order to include the title view at the beginning, the Notification.Builder + has logic to hide that view whenever this title view is to be visible. + --> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:ellipsize="end" + android:fadingEdge="horizontal" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" + /> + + <include layout="@layout/notification_2025_top_line_views" /> + + </NotificationTopLineView> + + <LinearLayout + android:id="@+id/notification_main_column" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:clipChildren="false" + > + <com.android.internal.widget.MessagingLinearLayout + android:id="@+id/notification_messaging" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipChildren="false" + android:spacing="@dimen/notification_messaging_spacing" /> + </LinearLayout> + + </LinearLayout> + + <!-- Images --> + <com.android.internal.widget.MessagingLinearLayout + android:id="@+id/conversation_image_message_container" + android:layout_width="@dimen/notification_right_icon_size" + android:layout_height="@dimen/notification_right_icon_size" + android:layout_gravity="center_vertical|end" + android:layout_marginTop="@dimen/notification_right_icon_headerless_margin" + android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin" + android:layout_marginStart="@dimen/notification_right_icon_content_margin" + android:forceHasOverlappingRendering="false" + android:spacing="0dp" + android:clipChildren="false" + android:visibility="gone" + /> + + <ImageView + android:id="@+id/right_icon" + android:layout_width="@dimen/notification_right_icon_size" + android:layout_height="@dimen/notification_right_icon_size" + android:layout_gravity="center_vertical|end" + android:layout_marginTop="@dimen/notification_right_icon_headerless_margin" + android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin" + android:layout_marginStart="@dimen/notification_right_icon_content_margin" + android:background="@drawable/notification_large_icon_outline" + android:clipToOutline="true" + android:importantForAccessibility="no" + android:scaleType="centerCrop" + /> + + <FrameLayout + android:id="@+id/expand_button_touch_container" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="@dimen/notification_content_margin_end" + > + + <include layout="@layout/notification_2025_expand_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="top|end" + /> + + </FrameLayout> + + </LinearLayout> + + <include layout="@layout/notification_close_button" + android:id="@+id/close_button" + android:layout_width="@dimen/notification_close_button_size" + android:layout_height="@dimen/notification_close_button_size" + android:layout_gravity="top|end" /> + + </com.android.internal.widget.NotificationMaxHeightFrameLayout> + + <LinearLayout + android:id="@+id/notification_action_list_margin_target" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="-20dp" + android:clipChildren="false" + android:orientation="vertical"> + <include layout="@layout/notification_template_smart_reply_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" + android:layout_marginEnd="@dimen/notification_content_margin_end" /> + <include layout="@layout/notification_material_action_list" /> + </LinearLayout> +</LinearLayout> +</com.android.internal.widget.ConversationLayout> diff --git a/core/res/res/layout/notification_2025_template_collapsed_media.xml b/core/res/res/layout/notification_2025_template_collapsed_media.xml index 9959b666b3bf..5beab508aecf 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_media.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_media.xml @@ -104,7 +104,6 @@ android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" - android:textSize="@dimen/notification_2025_title_text_size" /> <include layout="@layout/notification_2025_top_line_views" /> diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml index 85ca124de8ff..d7c3263904d4 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml @@ -130,7 +130,6 @@ android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" - android:textSize="@dimen/notification_2025_title_text_size" /> <include layout="@layout/notification_2025_top_line_views" /> diff --git a/core/res/res/layout/notification_2025_template_compact_heads_up_base.xml b/core/res/res/layout/notification_2025_template_compact_heads_up_base.xml index 11fc48668ad7..52bc7b8ea3bb 100644 --- a/core/res/res/layout/notification_2025_template_compact_heads_up_base.xml +++ b/core/res/res/layout/notification_2025_template_compact_heads_up_base.xml @@ -69,7 +69,6 @@ android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" - android:textSize="@dimen/notification_2025_title_text_size" /> <include layout="@layout/notification_2025_top_line_views" /> </NotificationTopLineView> diff --git a/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml b/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml index bf70a5eff47e..cf9ff6bef6f8 100644 --- a/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml +++ b/core/res/res/layout/notification_2025_template_compact_heads_up_messaging.xml @@ -90,7 +90,6 @@ android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" - android:textSize="@dimen/notification_2025_title_text_size" /> <include layout="@layout/notification_2025_top_line_views" /> </NotificationTopLineView> diff --git a/core/res/res/layout/notification_2025_template_conversation.xml b/core/res/res/layout/notification_2025_template_conversation.xml deleted file mode 100644 index 24b6ad09d3f7..000000000000 --- a/core/res/res/layout/notification_2025_template_conversation.xml +++ /dev/null @@ -1,159 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2024 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License - --> - -<!-- extends FrameLayout --> -<com.android.internal.widget.ConversationLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/status_bar_latest_event_content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:clipChildren="false" - android:tag="conversation" - android:theme="@style/Theme.DeviceDefault.Notification" - > - - <include layout="@layout/notification_2025_conversation_icon_container" /> - - <!-- Wraps entire "expandable" notification --> - <com.android.internal.widget.RemeasuringLinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="top" - android:clipToPadding="false" - android:clipChildren="false" - android:orientation="vertical" - > - <!-- LinearLayout for Expand Button--> - <com.android.internal.widget.RemeasuringLinearLayout - android:id="@+id/expand_button_and_content_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_weight="1" - android:gravity="start|top" - android:orientation="horizontal" - android:clipChildren="false" - android:clipToPadding="false"> - <!--TODO: move this into a separate layout and share logic with the header to bring back app opps etc--> - <com.android.internal.widget.RemeasuringLinearLayout - android:id="@+id/notification_action_list_margin_target" - android:layout_width="0dp" - android:orientation="vertical" - android:layout_height="wrap_content" - android:layout_weight="1"> - - <!-- Header --> - - <!-- Use layout_marginStart instead of paddingStart to work around strange - measurement behavior on lower display densities. --> - <include - layout="@layout/notification_2025_conversation_header" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="2dp" - android:layout_marginStart="@dimen/notification_2025_content_margin_start" - /> - - <!-- Messages --> - <com.android.internal.widget.MessagingLinearLayout - android:id="@+id/notification_messaging" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:minHeight="@dimen/notification_text_size" - android:spacing="@dimen/notification_messaging_spacing" - android:clipToPadding="false" - android:clipChildren="false" - /> - </com.android.internal.widget.RemeasuringLinearLayout> - - <!-- This is where the expand button container will be placed when collapsed--> - </com.android.internal.widget.RemeasuringLinearLayout> - - <include layout="@layout/notification_template_smart_reply_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_content_margin" - android:layout_marginStart="@dimen/notification_2025_content_margin_start" - android:layout_marginEnd="@dimen/notification_content_margin_end" /> - <include layout="@layout/notification_material_action_list" /> - </com.android.internal.widget.RemeasuringLinearLayout> - - <!--expand_button_a11y_container ensures talkback focus order is correct when view is expanded. - The -1px of marginTop and 1px of paddingTop make sure expand_button_a11y_container is prior to - its sibling view in accessibility focus order. - {see android.view.ViewGroup.addChildrenForAccessibility()} - expand_button_container will be moved under expand_button_and_content_container when collapsed, - this dynamic movement ensures message can flow under expand button when expanded--> - <FrameLayout - android:id="@+id/expand_button_a11y_container" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="end|top" - android:clipChildren="false" - android:clipToPadding="false" - android:layout_marginTop="-1px" - android:paddingTop="1px" - > - <!--expand_button_container is dynamically placed between here and at the end of the - layout. It starts here since only FrameLayout layout params have gravity--> - <LinearLayout - android:id="@+id/expand_button_container" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_gravity="end|top" - android:clipChildren="false" - android:clipToPadding="false" - android:orientation="vertical"> - <include layout="@layout/notification_close_button" - android:layout_width="@dimen/notification_close_button_size" - android:layout_height="@dimen/notification_close_button_size" - android:layout_gravity="end" - android:layout_marginEnd="20dp" - /> - <!--expand_button_touch_container makes sure that we can nicely center the expand - content in the collapsed layout while the parent makes sure that we're never laid out - bigger than the messaging content.--> - <LinearLayout - android:id="@+id/expand_button_touch_container" - android:layout_width="wrap_content" - android:layout_height="@dimen/conversation_expand_button_height" - android:orientation="horizontal" - android:layout_gravity="end|top" - android:paddingEnd="0dp" - android:clipToPadding="false" - android:clipChildren="false" - > - <!-- Images --> - <com.android.internal.widget.MessagingLinearLayout - android:id="@+id/conversation_image_message_container" - android:forceHasOverlappingRendering="false" - android:layout_width="40dp" - android:layout_height="40dp" - android:layout_marginStart="@dimen/conversation_image_start_margin" - android:spacing="0dp" - android:layout_gravity="center" - android:clipToPadding="false" - android:clipChildren="false" - /> - <include layout="@layout/notification_2025_expand_button" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="top|end" - /> - </LinearLayout> - </LinearLayout> - </FrameLayout> -</com.android.internal.widget.ConversationLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_call.xml b/core/res/res/layout/notification_2025_template_expanded_call.xml index 0be61253c917..2114831f4c15 100644 --- a/core/res/res/layout/notification_2025_template_expanded_call.xml +++ b/core/res/res/layout/notification_2025_template_expanded_call.xml @@ -55,7 +55,7 @@ > <include - layout="@layout/notification_2025_conversation_header" + layout="@layout/notification_template_conversation_header" android:layout_width="wrap_content" android:layout_height="wrap_content" /> diff --git a/core/res/res/layout/notification_2025_template_expanded_conversation.xml b/core/res/res/layout/notification_2025_template_expanded_conversation.xml new file mode 100644 index 000000000000..d7e8bb3b6da2 --- /dev/null +++ b/core/res/res/layout/notification_2025_template_expanded_conversation.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<!-- extends FrameLayout --> +<com.android.internal.widget.ConversationLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/status_bar_latest_event_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipToPadding="false" + android:clipChildren="false" + android:tag="conversation" + > + + <include layout="@layout/notification_2025_conversation_header"/> + + <com.android.internal.widget.RemeasuringLinearLayout + android:id="@+id/notification_action_list_margin_target" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="top" + android:clipChildren="false" + android:orientation="vertical"> + + <!-- Note: the top margin is being set in code based on the estimated space needed for + the header text. --> + <com.android.internal.widget.RemeasuringLinearLayout + android:id="@+id/notification_main_column" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="top" + android:layout_weight="1" + android:layout_marginEnd="@dimen/notification_content_margin_end" + android:orientation="vertical" + android:clipChildren="false" + > + + <include layout="@layout/notification_template_part_line1"/> + + <com.android.internal.widget.MessagingLinearLayout + android:id="@+id/notification_messaging" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipChildren="false" + android:spacing="@dimen/notification_messaging_spacing" /> + </com.android.internal.widget.RemeasuringLinearLayout> + + <include layout="@layout/notification_template_smart_reply_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/notification_content_margin" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" + android:layout_marginEnd="@dimen/notification_content_margin_end" /> + + <include layout="@layout/notification_material_action_list" /> + + </com.android.internal.widget.RemeasuringLinearLayout> + + <include layout="@layout/notification_template_right_icon" /> + +</com.android.internal.widget.ConversationLayout> diff --git a/core/res/res/layout/notification_2025_template_expanded_messaging.xml b/core/res/res/layout/notification_2025_template_expanded_messaging.xml index 177706c6d58d..20abfee6a4b6 100644 --- a/core/res/res/layout/notification_2025_template_expanded_messaging.xml +++ b/core/res/res/layout/notification_2025_template_expanded_messaging.xml @@ -36,17 +36,21 @@ android:clipChildren="false" android:orientation="vertical"> + <!-- Note: the top margin is being set in code based on the estimated space needed for + the header text. --> <com.android.internal.widget.RemeasuringLinearLayout android:id="@+id/notification_main_column" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_weight="1" - android:layout_marginTop="@dimen/notification_2025_header_height" android:layout_marginEnd="@dimen/notification_content_margin_end" android:orientation="vertical" android:clipChildren="false" > + + <include layout="@layout/notification_template_part_line1"/> + <com.android.internal.widget.MessagingLinearLayout android:id="@+id/notification_messaging" android:layout_width="match_parent" diff --git a/core/res/res/layout/notification_2025_top_line_views.xml b/core/res/res/layout/notification_2025_top_line_views.xml index 74873463391e..a9bde9d48dcf 100644 --- a/core/res/res/layout/notification_2025_top_line_views.xml +++ b/core/res/res/layout/notification_2025_top_line_views.xml @@ -20,7 +20,7 @@ <merge xmlns:android="http://schemas.android.com/apk/res/android"> - <TextView + <com.android.internal.widget.ObservableTextView android:id="@+id/app_name_text" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml index 149a5a9568f2..2df1725e7234 100644 --- a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml +++ b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml @@ -45,6 +45,7 @@ android:maxDrawableWidth="@dimen/notification_icon_circle_size" android:maxDrawableHeight="@dimen/notification_icon_circle_size" android:scaleType="centerCrop" + android:visibility="gone" android:importantForAccessibility="no" /> <ViewStub diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 5da0924c08c3..788d5f7c80d2 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"toegang te verkry tot sensordata oor jou lewenstekens"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Kennisgewings"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"wys kennisgewings"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Venster-inhoud ophaal"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Die inhoud ondersoek van \'n venster waarmee jy interaksie het."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Verken-met-raak aanskakel"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Laat die app toe om jou fotoversameling te wysig."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lees liggings in jou mediaversameling"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Laat die app toe om liggings in jou mediaversameling te lees."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gebruik biometrie"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gebruik biometrie of skermslot"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifieer dat dit jy is"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-paneel middel"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Outoklik-tipe instellingspaneel"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Linksklik"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Regsklik"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dubbelklik"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Sleep"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rollees"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Onderbreek"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisie"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index c55f1c63bf04..ca145e58b22d 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"ስለአስፈላጊ ምልክቶችዎ ያሉ የዳሳሽ ውሂብ ይድረሱ"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"ማሳወቂያዎች"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"ማሳወቂያዎች አሳይ"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"የመስኮት ይዘት ሰርስረው ያውጡ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"መስተጋበር የሚፈጥሩት የመስኮት ይዘት ይመርምሩ።"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"በመንካት ያስሱን ያብሩ"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"መተግበሪያው የፎቶ ስብስብዎን እንዲቀይረው ያስችለዋል።"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"አካባቢዎችን ከሚዲያ ስብስብዎ ማንበብ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"መተግበሪያው አካባቢዎችን ከሚዲያ ስብስብዎ እንዲያነብብ ያስችለዋል።"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ባዮሜትሪኮችን ይጠቀሙ"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ባዮሜትሪክስ ወይም ማያ ገፅ መቆለፊያን ይጠቀሙ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"እርስዎን መሆንዎን ያረጋግጡ"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"የDpad ማዕከል"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"የራስ-ሰር ጠቅ ማድረግ ትየባ ቅንብሮች ፓነል"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"የግራ ጠቅታ"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"የቀኝ ጠቅታ"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ድርብ ጠቅ አድርግ"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ጎትት"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ሸብልል"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ባለበት አቁም"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"አቀማመጥ"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index f542d439bf2e..24d628a3e29b 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -357,6 +357,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"الوصول إلى بيانات المستشعر حول علاماتك الحيوية"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"الإشعارات"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"عرض الإشعارات"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"استرداد محتوى النافذة:"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"فحص محتوى نافذة يتم التفاعل معها."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"تفعيل الاستكشاف باللمس:"</string> @@ -652,6 +660,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"للسماح للتطبيق بتعديل مجموعة صورك."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"قراءة المواقع من مجموعة الوسائط التابعة لك"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"للسماح للتطبيق بقراءة المواقع من مجموعة الوسائط التابعة لك."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"استخدام المقاييس الحيوية"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استخدام المقاييس الحيوية أو قفل الشاشة"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"تأكيد هويتك"</string> @@ -1157,7 +1197,7 @@ <string name="year" msgid="5182610307741238982">"سنة"</string> <string name="years" msgid="5797714729103773425">"أعوام"</string> <string name="now_string_shortest" msgid="3684914126941650330">"الآن"</string> - <string name="duration_minutes_shortest" msgid="5744379079540806690">"<xliff:g id="COUNT">%d</xliff:g> دقيقة"</string> + <string name="duration_minutes_shortest" msgid="5744379079540806690">"<xliff:g id="COUNT">%d</xliff:g> د"</string> <string name="duration_hours_shortest" msgid="1477752094141971675">"<xliff:g id="COUNT">%d</xliff:g> ساعة"</string> <string name="duration_days_shortest" msgid="4083124701676227233">"<xliff:g id="COUNT">%d</xliff:g> يوم"</string> <string name="duration_years_shortest" msgid="483982719231145618">"<xliff:g id="COUNT">%d</xliff:g> سنة"</string> @@ -1973,7 +2013,7 @@ <string name="zen_mode_rule_name_combination" msgid="7174598364351313725">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string> <string name="toolbar_collapse_description" msgid="8009920446193610996">"تصغير"</string> <string name="zen_mode_feature_name" msgid="3785547207263754500">"عدم الإزعاج"</string> - <string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"التعطل"</string> + <string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"فترة التوقّف"</string> <string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"ليلة يوم من أيام الأسبوع"</string> <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"نهاية الأسبوع"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"حدث"</string> @@ -2251,14 +2291,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"الزرّ المركزي"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"لوحة إعدادات نوع النقر التلقائي"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"النقر بالزر الأيسر"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"النقر بزر الماوس الأيمن"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"النقر مرّتين"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"سحب"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"الانتقال للأسفل أو للأعلى"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"إيقاف مؤقت"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"تعديل الموضع"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index b8afd2edc2e1..397afe20abb2 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"আপোনাৰ দেহৰ গুৰুত্বপূৰ্ণ অংগসমূহৰ অৱস্থাৰ বিষয়ে ছেন্সৰৰ ডেটা লাভ কৰিব পাৰে"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"জাননী"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"জাননী দেখুৱাওক"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ৱিণ্ড’ সমল বিচাৰি উলিওৱাৰ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"আপুনি চাই থকা ৱিণ্ড’খনৰ সমল পৰীক্ষা কৰাৰ।"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"স্পৰ্শৰ দ্বাৰা অন্বেষণ কৰাৰ সুবিধা অন কৰাৰ"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"এপক আপোনাৰ ফট’ সংগ্ৰহ সালসলনি কৰিবলৈ দিয়ে।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"এপক আপোনাৰ মিডিয়া সংগ্ৰহৰ অৱস্থান পঢ়িবলৈ দিয়ে।"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"বায়\'মেট্ৰিক ব্যৱহাৰ কৰক"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"বায়\'মেট্ৰিক অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"এইয়া আপুনিয়েই বুলি সত্যাপন কৰক"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ডিপেডৰ মাজৰ বুটাম"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"প্ৰকাৰৰ ছেটিঙৰ পেনেলত স্বয়ংক্ৰিয়ভাৱে ক্লিক কৰক"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"বাওঁফালৰ ক্লিক"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"সোঁফালৰ ক্লিক"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"দুবাৰ ক্লিক"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"টানি আনি এৰক"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"স্ক্ৰ’ল কৰক"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"পজ কৰক"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"স্থান"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index affa56954001..96c77e4ee030 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"Həyati əlamətlər haqqında sensor dataya daxil olun"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Bildirişlər"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"bildirişləri göstərmək"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Pəncərənin məzmununu əldə edin"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Əlaqədə olduğunuz pəncərənin məzmununu nəzərdən keçirin."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Toxunuşla öyrənmə funksiyasını aktiv edin"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tətbiqin foto kolleksiyanıza düzəliş etməsinə icazə verir."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"media kolleksiyanızdan məkanları oxuyun"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Tətbiqin media kolleksiyanızdan məkanları oxumasına icazə verin."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrik məlumatlardan istifadə edin"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrik məlumatlardan və ya ekran kilidindən istifadə edin"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Kimliyinizi doğrulayın"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Mərkəzə"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Avtomatik klikləmə növü üzrə ayarlar paneli"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Sola klik"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Sağ düymə ilə toxunun"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"İki dəfə toxunun"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Çəkin"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Sürüşdürün"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Durdurun"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Mövqe"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 3acc8df73a83..6a68f8d76e30 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"pristupa podacima senzora o vitalnim funkcijama"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Obaveštenja"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"prikazivanje obaveštenja"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"da preuzima sadržaj prozora"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Proverava sadržaj prozora sa kojim ostvarujete interakciju."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"da uključi Istraživanja dodirom"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Dozvoljava aplikaciji da menja kolekciju slika."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz medijske kolekcije"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Dozvoljava aplikaciji da čita lokacije iz medijske kolekcije."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Koristite biometriju"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Koristite biometriju ili otključavanje ekrana"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite identitet"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 7c827bbecaab..69271ba47c0a 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -355,6 +355,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"атрымліваць з датчыка даныя асноўных фізіялагічных паказчыкаў"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Апавяшчэнні"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"паказваць апавяшчэнні"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Атрымліваць змесціва вакна"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Аналізаваць змесціва актыўнага вакна."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Уключаць Азнаямленне дотыкам"</string> @@ -650,6 +658,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Праграма зможа змяняць фотакалекцыю."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"паказваць месцазнаходжанне ў калекцыі мультымедыя"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Праграма зможа паказваць месцазнаходжанне ў калекцыі мультымедыя."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Выкарыстоўваць біяметрыю"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Выкарыстоўваць біяметрыю ці блакіроўку экрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Спраўдзіце, што гэта вы"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index c3a271267a36..1581ab8a5545 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"достъп до сензорните данни за жизнените ви показатели"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Известия"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"показване на известията"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Извлича съдържанието от прозореца"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Инспектира съдържанието на прозорец, с който взаимодействате."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Включи изследването чрез докосване"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Разрешава на приложението да променя колекцията ви от снимки."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"да чете местоположенията от мултимедийната ви колекция"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Разрешава на приложението да чете местоположенията от мултимедийната ви колекция."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Използване на биометр. данни"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Използване на биометрични данни или опцията за заключване на екрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Потвърдете, че сте вие"</string> @@ -1409,7 +1449,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Поставена е нова SIM карта"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Докоснете, за да я настроите"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Часовата ви зона се промени"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Вече сте в зоната <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Вече сте във: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Задаване на часа"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Задаване на дата"</string> <string name="date_time_set" msgid="4603445265164486816">"Задаване"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Контролен пад – център"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Панел с настройки за типа на автоматичното кликване"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Кликване с ляв бутон"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Кликване с десния бутон"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Кликване два пъти"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Преместване с плъзгане"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Превъртане"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Пауза"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Позиция"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index f6492c5b9ef3..c05ea6dcbf00 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"আপনার অত্যাবশ্যক লক্ষণগুলির সম্পর্কে সেন্সর ডেটা অ্যাক্সেস করে"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"বিজ্ঞপ্তি"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"বিজ্ঞপ্তি দেখুন"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"উইন্ডোর কন্টেন্ট ফিরিয়ে আনুন"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ব্যবহার করছেন এমন একটি উইন্ডোর কন্টেন্ট পরীক্ষা করে৷"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"স্পর্শের মাধ্যমে অন্বেষণ করা চালু করুন"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"অ্যাপকে আপনার ফটো সংগ্রহ পরিবর্তন করার অনুমতি দিন।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ডিয়া সংগ্রহ থেকে লোকেশন দেখতে দিন"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"আপনার মিডিয়া সংগ্রহ থেকে লোকেশন দেখতে অ্যাপকে অনুমতি দিন।"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"বায়োমেট্রিক্স ব্যবহার করুন"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"বায়োমেট্রিক্স অথবা স্ক্রিন লক ব্যবহার করুন"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"আপনার পরিচয় যাচাই করুন"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"ডিপ্যাড (Dpad)-এর মাঝখানে"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"অটোক্লিক টাইপ সেটিংস প্যানেল"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"বাঁদিকের বোতামে ক্লিক করুন"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"মাউসের ডানদিকের বোতামে ক্লিক করুন"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ডবল ক্লিক করুন"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"টেনে আনুন"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"স্ক্রল করুন"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"পজ করুন"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"পজিশন"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 3ff85acf48a0..ebef234f02bc 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"pristupa podacima senzora o vašim vitalnim funkcijama"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Obavještenja"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"prikaz obavještenja"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"preuzimati sadržaj prozora"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Pregleda sadržaj prozora koji trenutno koristite."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"uključiti Istraživanje dodirom"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Omogućava aplikaciji da mijenja vašu kolekciju fotografija."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz kolekcije medija"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Omogućava aplikaciji da čita lokacije iz vaše kolekcije medija."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Koristi biometriju"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Koristi biometriju ili zaključavanje ekrana"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite identitet"</string> @@ -2250,8 +2290,8 @@ <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Lijevi klik"</string> <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Desni klik"</string> <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dvostruki klik"</string> - <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Povuci"</string> - <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Pomakni se"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Prevlačenje"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Klizanje"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauziraj"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Položaj"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 9b61887da0bd..6ddfeaf18d00 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"accedir a les dades del sensor sobre les constants vitals"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificacions"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostra notificacions"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperar el contingut de la finestra"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspeccionar el contingut d\'una finestra amb què estàs interaccionant."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Activar Exploració tàctil"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permet que l\'aplicació modifiqui la teva col·lecció de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"llegir les ubicacions de les teves col·leccions multimèdia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permet que l\'aplicació llegeixi les ubicacions de les teves col·leccions multimèdia."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilitza la biometria"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Fes servir la biometria o el bloqueig de pantalla"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la teva identitat"</string> @@ -2248,14 +2288,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Creu direccional: centre"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Tauler de configuració del tipus de clic automàtic"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic esquerre"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Fes clic amb el botó dret"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Fes doble clic"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Arrossega"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Desplaça"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Posa en pausa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posició"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 9c8cc9a17878..5e596fc0d4c5 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -355,6 +355,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"přístup k datům ze senzorů vašich životních funkcí"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Oznámení"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"zobrazovat oznámení"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Načítat obsah oken"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Může prozkoumávat obsah oken, se kterými pracujete."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Zapnout funkci Prozkoumání dotykem"</string> @@ -650,6 +658,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Umožňuje aplikaci upravit vaši sbírku fotek."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čtení míst ze sbírky médií"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Umožňuje aplikaci číst místa z vaší sbírky médií."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Použít biometrii"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Použít biometrii nebo zámek obrazovky"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrďte, že jste to vy"</string> @@ -2090,12 +2130,9 @@ <string name="unpin_target" msgid="3963318576590204447">"Odepnout"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"Odepnout: <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="app_info" msgid="6113278084877079851">"O aplikaci"</string> - <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) --> - <skip /> - <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) --> - <skip /> - <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) --> - <skip /> + <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Přímé sdílení cílů"</string> + <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Návrhy aplikací"</string> + <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Seznam aplikací"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"Spouštění ukázky…"</string> <string name="demo_restarting_message" msgid="1160053183701746766">"Resetování zařízení…"</string> @@ -2252,14 +2289,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad střed"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel nastavení typu automatického kliknutí"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Kliknutí levým"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Kliknutí pravým tlačítkem"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dvojité kliknutí"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Přetažení"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Posunutí"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pozastavit"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozice"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string> @@ -2536,12 +2569,8 @@ <string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Mapy"</string> <string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Aplikace"</string> <string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Vaše otisky prstů se nedaří rozpoznat. Nastavte odemknutí otiskem prstu znovu."</string> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) --> - <skip /> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) --> - <skip /> + <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Zařízení USB bylo připojeno, když bylo zařízení zamknuté"</string> + <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Zařízení USB bylo připojeno, když byl Android zamknutý. Pokud zařízení chcete používat, nejdříve Android odemkněte a pak zařízení USB připojte znovu."</string> + <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Podezřelá aktivita USB"</string> + <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Datový signál USB byl deaktivován."</string> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 1b96dbbe07f7..8cc1cfe2a277 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"få adgang til sensordata om dine vitale værdier"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifikationer"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"vise notifikationer"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Hente indholdet i vinduet"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Undersøge indholdet i et vindue, du interagerer med."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Aktivere Udforsk ved berøring"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tillader, at appen kan ændre din billedsamling."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"læse lokationer fra din mediesamling"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Tillader, at appen kan læse lokationer fra din mediesamling."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Brug biometri"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Brug biometri eller skærmlås"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verificer, at det er dig"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad, midten"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel med indstillinger for type af automatisk klik"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Venstreklik"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Højreklik"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dobbeltklik"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Træk"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rul"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sæt på pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Placering"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 73e7b9a9c0c8..7d5672b6fb16 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"auf Sensordaten zu deinen Vitaldaten zugreifen"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Benachrichtigungen"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"Benachrichtigungen anzeigen"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Fensterinhalte abrufen"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Die Inhalte eines Fensters, mit dem du interagierst, werden abgerufen."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"\"Tippen & Entdecken\" aktivieren"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ermöglicht der App, deine Fotosammlung zu ändern."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"Standorte aus meiner Mediensammlung abrufen"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Ermöglicht der App, Standorte aus deiner Mediensammlung abzurufen."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrisches Verfahren nutzen"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrisches Verfahren oder Displaysperre verwenden"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Deine Identität bestätigen"</string> @@ -1409,7 +1449,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Neue SIM-Karte eingelegt"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Zum Einrichten tippen"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Die Zeitzone hat sich geändert"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Du bist jetzt in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Du bist jetzt in: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Uhrzeit festlegen"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Datum festlegen"</string> <string name="date_time_set" msgid="4603445265164486816">"Speichern"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Steuerkreuz Mitte"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Bereich mit Einstellungen für automatische Klicks"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Linksklick"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Rechtsklicken"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Doppelklicken"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Ziehen"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scrollen"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausieren"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string> @@ -2430,8 +2466,8 @@ <string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string> <string name="permlab_companionProfileWatch" msgid="2457738382085872542">"Berechtigung für Companion-Smartwatch-Profil zum Verwalten von Smartwatches"</string> <string name="permdesc_companionProfileWatch" msgid="5655698581110449397">"Ermöglicht einer Companion-App, Smartwatches zu verwalten."</string> - <string name="permlab_observeCompanionDevicePresence" msgid="9008994909653990465">"Präsenz von Companion-Geräten beobachten"</string> - <string name="permdesc_observeCompanionDevicePresence" msgid="3011699826788697852">"Ermöglicht einer Companion-App, die Präsenz von Companion-Geräten zu beobachten, wenn sie in der Nähe oder weit entfernt sind."</string> + <string name="permlab_observeCompanionDevicePresence" msgid="9008994909653990465">"Präsenz von Begleitgeräten beobachten"</string> + <string name="permdesc_observeCompanionDevicePresence" msgid="3011699826788697852">"Ermöglicht einer Companion-App, die Präsenz von Begleitgeräten zu beobachten, wenn sie in der Nähe oder weit entfernt sind."</string> <string name="permlab_deliverCompanionMessages" msgid="3931552294842980887">"Companion-Nachrichten senden"</string> <string name="permdesc_deliverCompanionMessages" msgid="2170847384281412850">"Ermöglicht einer Companion-App, Companion-Nachrichten an andere Geräte zu senden."</string> <string name="permlab_startForegroundServicesFromBackground" msgid="6363004936218638382">"Dienste im Vordergrund aus dem Hintergrund starten"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 25a787c5d06b..84ca5b7808b7 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"πρόσβαση στα δεδομένα αισθητήρα σχετικά με τις ζωτικές ενδείξεις σας"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Ειδοποιήσεις"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"εμφάνιση ειδοποιήσεων"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Ανάκτηση του περιεχομένου του παραθύρου"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Έλεγχος του περιεχομένου ενός παραθύρου με το οποίο αλληλεπιδράτε."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Ενεργοποίηση της \"Εξερεύνησης με άγγιγμα\""</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Επιτρέπει στην εφαρμογή να τροποποιήσει τη συλλογή φωτογραφιών σας."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ανάγνωση τοποθεσιών από τη συλλογή πολυμέσων σας"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Επιτρέπει στην εφαρμογή να διαβάσει τοποθεσίες από τη συλλογή πολυμέσων σας."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Χρήση βιομετρικών"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Χρήση βιομετρικών ή κλειδώματος οθόνης"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Επαλήθευση ταυτότητας"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad κέντρο"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Πλαίσιο ρυθμίσεων τύπου αυτόματου κλικ"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Αριστερό κλικ"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Δεξί κλικ"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Διπλό κλικ"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Μεταφορά"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Κύλιση"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Παύση"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Θέση"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 886befff643f..ef7238ce249e 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"access sensor data about your vital signs"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifications"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"show notifications"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Retrieve window content"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window you\'re interacting with."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Turn on Explore by Touch"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Autoclick type settings panel"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Left-click"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Right-click"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Double-click"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Drag"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 33bbc6faba3f..7e837390ad98 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"access sensor data about your vital signs"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifications"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"show notifications"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Retrieve window content"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window you\'re interacting with."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Turn on Explore by Touch"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify it’s you"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index f0a9c2a27ddc..5b99b57a0d40 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"access sensor data about your vital signs"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifications"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"show notifications"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Retrieve window content"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window that you\'re interacting with."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Turn on Explore by Touch"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Autoclick type settings panel"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Left-click"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Right-click"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Double-click"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Drag"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 8fcb412154cc..5ba765bc68de 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"access sensor data about your vital signs"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifications"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"show notifications"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Retrieve window content"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspect the content of a window you\'re interacting with."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Turn on Explore by Touch"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Allows the app to modify your photo collection."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"read locations from your media collection"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Allows the app to read locations from your media collection."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Use biometrics"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Use biometrics or screen lock"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verify that it’s you"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centre"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Autoclick type settings panel"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Left-click"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Right-click"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Double-click"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Drag"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index f46a4d4abb40..d3258dde6721 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acceder a los datos de sensores acerca de tus signos vitales"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificaciones"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostrar notificaciones"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperar el contenido de las ventanas"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspeccionará el contenido de la ventana con la que estés interactuando."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Activar la Exploración táctil"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que la app modifique tu colección de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"leer ubicaciones de tu colección de contenido multimedia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que la app lea las ubicaciones de tu colección de contenido multimedia."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar datos biométricos"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar datos biométricos o bloqueo de pantalla"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Comprueba que eres tú"</string> @@ -2248,14 +2288,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pad direccional: centro"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel de configuración del tipo de clic automático"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic izquierdo"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Clic con botón derecho"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Hacer doble clic"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Arrastrar"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Desplazamiento"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el bucket RESTRICTED"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index d5948972ec9c..c021a8afde4f 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acceder a datos de sensores de tus constantes vitales"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificaciones"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostrar notificaciones"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Comprobar el contenido de la ventana"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspecciona el contenido de una ventana con la que estés interactuando."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Activar la exploración táctil"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que la aplicación modifique tu colección de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"leer las ubicaciones de tu colección de contenido multimedia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que la aplicación lea las ubicaciones de tu colección de contenido multimedia."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar biometría"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometría o bloqueo de pantalla"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica que eres tú"</string> @@ -1410,7 +1450,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Nueva SIM insertada"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Toca para configurar"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Tu zona horaria ha cambiado"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Ahora estás en <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Ahora estás en la <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Establecer hora"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Establecer fecha"</string> <string name="date_time_set" msgid="4603445265164486816">"Establecer"</string> @@ -2248,14 +2288,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Cruceta: centro"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel de ajustes del tipo de clic automático"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic izquierdo"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Hacer clic con el botón derecho"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Hacer doble clic"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Arrastrar"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Desplazarse"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausar"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 5e961f4fcae8..ae215833cdd6 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"juurdepääs anduri andmetele teie eluliste näitajate kohta"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Märguanded"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"märguannete kuvamine"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Akna sisu toomine"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Kasutatava akna sisu kontrollimine."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Puudutusega sirvimise sisselülitamine"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Võimaldab rakendusel muuta teie fotokogu."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"Lugeda teie meediakogus olevaid asukohti"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Võimaldab rakendusel lugeda teie meediakogus olevaid asukohti."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biomeetria kasutamine"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biomeetria või ekraaniluku kasutamine"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Kinnitage oma isik"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 0e450d1a0a4e..a78754ff28c5 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"atzitu bizi-konstanteei buruzko sentsorearen datuak"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Jakinarazpenak"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"jakinarazpenak erakutsi"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Leihoko edukia eskuratu."</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Arakatu irekita daukazun leihoko edukia."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"\"Arakatu ukituta\" aktibatu."</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Argazki bilduma aldatzeko baimena ematen dio aplikazioari."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"multimedia-edukien bildumako kokapena irakurri"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Multimedia-edukien bildumako kokapena irakurtzeko baimena ematen dio aplikazioari."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Erabili sistema biometrikoak"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Erabili sistema biometrikoak edo pantailaren blokeoa"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Egiaztatu zeu zarela"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Norabide-kontrolagailuko erdiko botoia"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automatikoki klik egiteko eginbide motaren ezarpenen panela"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Egin klik ezkerreko botoiarekin"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Egin klik eskuineko botoiarekin"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Egin klik bikoitza"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Arrastatu"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Egin gora eta behera"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausatu"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Ezarri posizioan"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 4334713515d9..ddde0b28b685 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"دسترسی به دادههای حسگر در رابطه با علائم حیاتی شما"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"اعلانها"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"نمایش اعلان"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"محتوای پنجره را بازیابی کند"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"محتوای پنجرهای را که درحال تعامل با آن هستید بررسی میکند."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"فعالسازی کاوش لمسی"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"به برنامه اجازه میدهد مجموعه عکستان را تغییر دهد."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"خواندن مکانها از مجموعه رسانه شما"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"به برنامه اجازه میدهد مکانها را از مجموعه رسانهتان بخواند."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"استفاده از دادههای زیستسنجشی"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"استفاده از دادههای زیستسنجشی یا قفل صفحه"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"تأیید کنید این شمایید"</string> @@ -2514,7 +2554,7 @@ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"راهاندازی"</string> <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"حالا نه"</string> <string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"زنگ هشدار برای <xliff:g id="USER_NAME">%s</xliff:g>"</string> - <string name="bg_user_sound_notification_button_switch_user" msgid="3091969648572788946">"تغییر کاربر"</string> + <string name="bg_user_sound_notification_button_switch_user" msgid="3091969648572788946">"تعویض کاربر"</string> <string name="bg_user_sound_notification_button_mute" msgid="4942158515665615243">"بیصدا کردن"</string> <string name="bg_user_sound_notification_message" msgid="8613881975316976673">"برای بیصدا کردن، تکضرب بزنید"</string> <string name="keyboard_shortcut_group_applications_browser" msgid="6535007304687100909">"مرورگر"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 5e3913e86d8b..b17ab2388413 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"pääsy anturidataan elintoiminnoistasi"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Ilmoitukset"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"näyttää ilmoituksia"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Noutaa ikkunan sisältöä"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Tarkistaa käyttämäsi ikkunan sisältö."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Ottaa kosketuksella tutkimisen käyttöön"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Antaa sovelluksen muokata kuvakokoelmaasi."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lukea mediakokoelmasi sijainteja"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Antaa sovelluksen lukea mediakokoelmasi sijainteja."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Käytä biometriikkaa"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Käytä biometriikkaa tai näytön lukitusta"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Vahvista henkilöllisyytesi"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Suuntanäppäimistö: keskipainike"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automaattisen klikkaustyypin asetuspaneeli"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Ykköspainike"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Klikkaa kakkospainikkeella"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Kaksoisklikkaa"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Vedä"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Vieritä"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Keskeytä"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Sijainti"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 6ef3e21c6a63..7145e5719298 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -74,7 +74,7 @@ <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string> <string name="page_size_compat_apk_warning" msgid="2982396798449041224">"Cette appli n\'est pas compatible avec les pages de 16 ko. La vérification de l\'alignement de fichiers APK a échoué. Cette appli sera exécutée en mode compatible avec la taille de la page. Pour une meilleure compatibilité, veuillez recompiler l\'application avec la prise en charge de pages de 16 ko. Pour en savoir plus, consultez la page <a href=\"https://developer.android.com/16kb-page-size\">https://developer.android.com/16kb-page-size</a>"</string> <string name="page_size_compat_elf_warning" msgid="6753874059564812651">"Cette appli n\'est pas compatible avec les pages de 16 ko. La vérification de l\'alignement de fichiers ELF a échoué. Cette appli sera exécutée en mode compatible avec la taille de la page. Pour une meilleure compatibilité, veuillez recompiler l\'application avec la prise en charge de pages de 16 ko. Pour en savoir plus, consultez la page <a href=\"https://developer.android.com/16kb-page-size\">https://developer.android.com/16kb-page-size</a>"</string> - <string name="page_size_compat_apk_and_elf_warning" msgid="7628675779500605390">"Cette appli n\'est pas compatible avec les pages de 16 ko. Les vérifications d\'alignement de fichiers APK et ELF ont échoué. Cette appli sera exécutée en mode compatible avec la taille de la page. Pour une meilleure compatibilité, veuillez recompiler l\'application avec la prise en charge de pages de 16 ko. Pour en savoir plus, consultez la page <a href=\"https://developer.android.com/16kb-page-size\">https://developer.android.com/16kb-page-size</a>"</string> + <string name="page_size_compat_apk_and_elf_warning" msgid="7628675779500605390">"Cette appli n\'est pas compatible avec les pages de 16 ko. Les vérifications de l\'alignement de fichiers APK et ELF ont échoué. Cette appli sera exécutée dans un mode compatible avec la taille de la page. Pour une compatibilité optimale, veuillez recompiler l\'application afin de prendre en charge les pages de 16 ko. Pour en savoir plus, consultez la page <a href=\"https://developer.android.com/16kb-page-size\">https://developer.android.com/16kb-page-size</a>"</string> <string name="serviceNotProvisioned" msgid="8289333510236766193">"Ce service n\'est pas pris en charge."</string> <string name="CLIRPermanent" msgid="166443681876381118">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string> <string name="auto_data_switch_title" msgid="3286350716870518297">"Données changées à <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string> @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"accéder aux données des capteurs sur vos signes vitaux"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifications"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"afficher les notifications"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Récupérer le contenu d\'une fenêtre"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspecter le contenu d\'une fenêtre avec laquelle vous interagissez."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Activer la fonctionnalité Explorer au toucher"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Autorise l\'appli à modifier votre collection de photos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lire les positions issues de votre collection multimédia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Autorise l\'appli à lire les positions indiquées dans votre collection multimédia."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utiliser les données biométriques"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utiliser les données biométriques ou le verrouillage de l\'écran"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez que c\'est vous"</string> @@ -2248,14 +2288,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pavé directionnel – centre"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panneau de configuration des paramètres de type clic automatique"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic gauche"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Clic droit"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Double-cliquer"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Glisser"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Faire défiler"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 4fd8601a1d8a..a71348ae832f 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"accéder aux données des capteurs relatives à vos signes vitaux"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifications"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"afficher des notifications"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Récupérer le contenu d\'une fenêtre"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspecte le contenu d\'une fenêtre avec laquelle vous interagissez."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Activer la fonctionnalité Explorer au toucher"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Autorise l\'application à modifier votre bibliothèque photo."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"consulter des positions issues de votre bibliothèque multimédia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Autorise l\'application à consulter des positions issues de votre bibliothèque multimédia."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utiliser la biométrie"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utiliser la biométrie ou le verrouillage de l\'écran"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmez votre identité"</string> @@ -2248,14 +2288,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Pavé directionnel - Centre"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panneau des paramètres du type de clic automatique"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic gauche"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Clic droit"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Double-cliquer"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Faire glisser"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Faire défiler"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string> @@ -2486,7 +2522,7 @@ <string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Retour"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"En attente…"</string> <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"SOS par satellite est maintenant disponible"</string> - <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Vous pouvez envoyer des messages aux services d\'urgence s\'il n\'y a pas de réseau mobile ou Wi-Fi. Google Messages doit être votre application de chat par défaut."</string> + <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Vous pouvez envoyer des messages aux services d\'urgence s\'il n\'y a pas de réseau mobile ou Wi-Fi. Google Messages doit être votre application de messagerie par défaut."</string> <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"SOS par satellite n\'est pas disponible"</string> <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"SOS par satellite n\'est pas disponible sur cet appareil"</string> <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"SOS par satellite n\'est pas configuré"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 4ce3fc33b7e9..e8090b8e16b4 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acceder aos datos dos sensores sobre as túas constantes vitais"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificacións"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostrar notificacións"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperar contido da ventá"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspecciona o contido dunha ventá coa que estás interactuando."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Activar a exploración táctil"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a aplicación modifique a túa colección de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler localizacións da túa colección multimedia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a aplicación lea as localizacións da túa colección multimedia."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Utilizar desbloqueo biométrico"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Utilizar desbloqueo biométrico ou credencial do dispositivo"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica a túa identidade"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Cruceta: centro"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel de configuración do tipo de clic automático"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic co botón esquerdo do rato"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Facer clic co botón dereito"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Facer dobre clic"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Arrastrar"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Desprazar"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posición"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index fcba3feb7819..3ddc9da52d23 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"તમારા મહત્વપૂર્ણ ચિહ્નો વિશે સેન્સર ડેટા ઍક્સેસ કરો"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"નોટિફિકેશન"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"નોટિફિકેશન બતાવો"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"વિંડો કન્ટેન્ટ પુનઃપ્રાપ્ત કરો"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"તમે જેની સાથે ક્રિયા-પ્રતિક્રિયા કરી રહ્યાં છો તે વિંડોનું કન્ટેન્ટ તપાસો."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"સ્પર્શ કરીને શોધખોળ કરવું ચાલુ કરો"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"એપને તમારો ફોટો સંગ્રહ સંશોધિત કરવાની મંજૂરી આપે છે."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"આપના મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવા"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"એપને તમારા મીડિયા સંગ્રહમાંથી સ્થાનો વાંચવાની મંજૂરી આપે છે."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"બાયોમેટ્રિક્સનો ઉપયોગ કરો"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"બાયોમેટ્રિક્સ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"આ તમે જ છો તેની ચકાસણી કરો"</string> @@ -1408,7 +1448,7 @@ <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"ઍપ ડાઉનલોડ કરો"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"નવું સિમ દાખલ કર્યું"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"તેને સેટ કરવા માટે ટૅપ કરો"</string> - <string name="time_zone_change_notification_title" msgid="5232503069219193218">"તમારો સમય ઝોન બદલાયો છે"</string> + <string name="time_zone_change_notification_title" msgid="5232503069219193218">"તમારો ટાઇમ ઝોન બદલાયો છે"</string> <string name="time_zone_change_notification_body" msgid="6135793674904665585">"તમે <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)માં છો"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"સમય સેટ કરો"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"તારીખ સેટ કરો"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 66f0ced39df6..a587509290dc 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"अपने महत्वपूर्ण संकेतों के बारे में सेंसर डेटा को ऐक्सेस करें"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"सूचनाएं"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"सूचनाएं दिखाएं"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विंडो का कॉन्टेंट वापस पाएं"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"विंडो पर नज़र आ रहे कॉन्टेंट की जांच करें."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"छूकर, किसी चीज़ से जुड़ी जानकारी सुनने की सुविधा चालू करें"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"इससे ऐप्लिकेशन को आपके फ़ोटो संग्रह में बदलाव करने की मंज़ूरी दी जाती है."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"अपने मीडिया संग्रह से जगह की जानकारी ऐक्सेस करने की अनुमति दें"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"इससे ऐप्लिकेशन को आपके मीडिया संग्रह से जगह की जानकारी ऐक्सेस करने की अनुमति दी जाती है."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"बायोमेट्रिक्स इस्तेमाल करें"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"बायोमेट्रिक्स या स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"अपनी पहचान की पुष्टि करें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index aadf1185883b..cfea6abb4dc8 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"pristupiti podacima senzora o vašim vitalnim znakovima"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Obavijesti"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"prikazati obavijesti"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Dohvaćati sadržaj prozora"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Pregledat će sadržaj prozora koji upotrebljavate."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Uključiti značajku Istraži dodirom"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Omogućuje aplikaciji izmjenu vaše zbirke fotografija."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čitanje lokacija iz vaše medijske zbirke"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Omogućuje aplikaciji čitanje lokacija iz vaše medijske zbirke."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Upotreba biometrije"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Upotreba biometrijske autentifikacije ili zaključavanja zaslona"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrdite da ste to vi"</string> @@ -1410,7 +1450,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Umetnuta je nova SIM kartica"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Dodirnite da biste je postavili"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Vaša je vremenska zona promijenjena"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Sada ste u vremenskoj zoni <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Trenutačna vremenska zona: <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Postavite vrijeme"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Postavi datum"</string> <string name="date_time_set" msgid="4603445265164486816">"Postavi"</string> @@ -2246,7 +2286,7 @@ <string name="accessibility_system_action_dpad_left_label" msgid="6557647179116479152">"Lijevo na plohi za smjerove"</string> <string name="accessibility_system_action_dpad_right_label" msgid="9180196950365804081">"Desno na plohi za smjerove"</string> <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"U središtu plohe za smjerove"</string> - <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Ploča postavki vrste automatskog klika"</string> + <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Ploča postavki automatskih klikova"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Lijevi klik"</string> <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Desni klik"</string> <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dvostruki klik"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 39a4cfcbe0c7..24389d6931b8 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"az érzékelők által mért, életjelekkel kapcsolatos adatok elérése"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Értesítések"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"értesítések megjelenítése"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Ablaktartalom lekérdezése"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"A használt ablak tartalmának vizsgálata."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Felfedezés érintéssel bekapcsolása"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Engedélyezi az alkalmazásnak a fényképgyűjtemény módosítását."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"helyek olvasása a médiagyűjteményből"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Engedélyezi az alkalmazásnak a helyek médiagyűjteményből való olvasását."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometriai feloldás használata"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"A folytatás biometriai feloldással vagy képernyőzárral lehetséges"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Igazolja, hogy Ön az"</string> @@ -1765,7 +1805,7 @@ <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Képernyő megtekintése és kezelése"</string> <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Elolvashatja a képernyő tartalmát, és tartalmakat jeleníthet meg más alkalmazások felett."</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Műveletek megtekintése és elvégzése"</string> - <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Követheti az alkalmazásokkal és hardveres érzékelőkkel való interakcióit, és műveleteket végezhet az alkalmazásokkal az Ön nevében."</string> + <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Követheti az appokkal és hardveres érzékelőkkel való interakcióit, és műveleteket végezhet az appokkal az Ön nevében."</string> <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Engedélyezés"</string> <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Tiltás"</string> <string name="accessibility_dialog_button_uninstall" msgid="2952465517671708108">"Eltávolítás"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"D-pad – középre"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automatikus kattintás típusának beállításai panel"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Kattintás bal egérgombbal"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Kattintás jobb egérgombbal"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Duplakattintás"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Húzás"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Görgetés"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Szüneteltetés"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozíció"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index f4b83f2a6540..1125dc9914e9 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"օգտագործել սենսորների տվյալները ձեր օրգանիզմի վիճակի մասին"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Ծանուցումներ"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"ցուցադրել ծանուցումներ"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Առբերել պատուհանի բովանդակությունը"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Վերլուծել գործող պատուհանի բովանդակությունը"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Միացնել Հպման միջոցով հետազոտումը"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Թույլ է տալիս հավելվածին փոփոխել ձեր լուսանկարների հավաքածուն:"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ճանաչել տեղադրության մասին տվյալները մեդիա բովանդակության հավաքածուից"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Կենսաչափական համակարգեր"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Օգտագործել կենսաչափական համակարգեր կամ էկրանի կողպում"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Հաստատեք ձեր ինքնությունը"</string> @@ -2088,12 +2128,9 @@ <string name="unpin_target" msgid="3963318576590204447">"Ապամրացնել"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"Ապամրացնել <xliff:g id="LABEL">%1$s</xliff:g> հավելվածը"</string> <string name="app_info" msgid="6113278084877079851">"Հավելվածի մասին"</string> - <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) --> - <skip /> - <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) --> - <skip /> - <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) --> - <skip /> + <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Direct Share-ի ստացողներ"</string> + <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Առաջարկվող հավելվածներ"</string> + <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Հավելվածների ցուցակ"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"Ցուցադրական օգտատերը գործարկվում է…"</string> <string name="demo_restarting_message" msgid="1160053183701746766">"Սարքը վերակայվում է…"</string> @@ -2250,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad-ի «Կենտրոն» կոճակ"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Ավտոմատ սեղմման տեսակի կարգավորումների վահանակ"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Ձախ սեղմում"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Սեղմել մկնիկի աջ կոճակը"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Երկու անգամ սեղմել"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Քաշել"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Ոլորել"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Դադարեցնել"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Դիրքը"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string> @@ -2534,12 +2567,8 @@ <string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Քարտեզներ"</string> <string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Հավելվածներ"</string> <string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Ձեր մատնահետքերն այլևս չեն կարող ճանաչվել։ Նորից կարգավորեք մատնահետքով ապակողպումը։"</string> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) --> - <skip /> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) --> - <skip /> + <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"Ապակողպեք Android սարքը"</string> + <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android սարքը կողպված է։ USB կրիչն օգտագործելու համար նախ ապակողպեք Android սարքը, այնուհետև նորից տեղադրեք կրիչը։"</string> + <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Հայտնաբերվել է կասկածելի USB կրիչ"</string> + <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB-ով տվյալների փոխանցումն անջատված է։"</string> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index ce9a7f6c6bea..2cd5472ccb7d 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"mengakses data sensor tentang tanda-tanda vital"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifikasi"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"tampilkan notifikasi"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Membaca konten di jendela"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Memeriksa konten di jendela yang sedang Anda buka."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Mengaktifkan Jelajahi dengan Sentuhan"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Mengizinkan aplikasi untuk memodifikasi koleksi foto Anda."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"membaca lokasi dari koleksi media Anda"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Mengizinkan aplikasi untuk membaca lokasi dari koleksi media Anda."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gunakan biometrik"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gunakan biometrik atau kunci layar"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifikasi diri Anda"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Tengah"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel setelan jenis klik otomatis"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Klik kiri"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Klik kanan"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Klik dua kali"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Tarik"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Jeda"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisi"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index b80efc7878f5..a89a50fe9c8b 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"aðgangur að skynjaragögnum um lífsmörk þín"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Tilkynningar"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"sýna tilkynningar"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Sækja innihald glugga"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Kanna innihald glugga sem þú ert að nota."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Kveikja á snertikönnun"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Leyfir forritinu að breyta myndasafninu þínu."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lesa staðsetningar úr efnissafninu þínu"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Leyfir forritinu að lesa staðsetningar úr efnissafninu þínu."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Nota lífkenni"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Nota lífkenni eða skjálás"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Staðfestu hver þú ert"</string> @@ -1409,7 +1449,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Nýtt SIM-kort sett í"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Ýttu til að setja það upp"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Tímabeltinu þínu var breytt"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Þú ert nú á <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Tímabeltið þitt er nú <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Veldu tíma"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Veldu dagsetningu"</string> <string name="date_time_set" msgid="4603445265164486816">"Velja"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Miðjuhnappur stýriflatar"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Stillingasvæði fyrir tegund sjálfvirks smells"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Vinstrismellur"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Hægrismella"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Tvísmella"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Draga"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Fletta"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Hlé"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Staðsetning"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 3ca9f7f8c7f1..47ef283523ec 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"Possono accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notifiche"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"Visualizzazione di notifiche"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Recuperare contenuti della finestra"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Esamina i contenuti di una finestra con cui interagisci."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Attivare Esplora al tocco"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Consente all\'app di modificare la tua raccolta di foto."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lettura delle posizioni dalla tua raccolta multimediale"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Consente all\'app di leggere le posizioni dalla tua raccolta multimediale."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usa la biometria"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usa la biometria o il blocco schermo"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifica la tua identità"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index cfa0987c15d4..d58084de0490 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"גישה אל נתוני חיישנים של הסימנים החיוניים שלך"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"התראות"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"הצגת התראות"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"אחזור תוכן של חלון"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"בדיקת התוכן של חלון שאיתו מתבצעת אינטראקציה."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"הפעלה של \'גילוי באמצעות מגע\'"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"מאפשרת לאפליקציה לשנות את אוסף התמונות שלך."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"לקרוא מיקומים מאוסף המדיה שלך"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"מאפשרת לאפליקציה לקרוא מיקומים מאוסף המדיה שלך."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"שימוש במידע ביומטרי"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"שימוש במידע ביומטרי בנעילת מסך"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"אימות הזהות שלך"</string> @@ -1433,7 +1473,7 @@ <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"המכשיר זיהה התקן אודיו אנלוגי"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ההתקן שחיברת לא תואם לטלפון הזה. יש ללחוץ לקבלת מידע נוסף."</string> <string name="adb_active_notification_title" msgid="408390247354560331">"ניפוי באגים ב-USB מחובר"</string> - <string name="adb_active_notification_message" msgid="5617264033476778211">"צריך ללחוץ כדי להשבית את ניפוי הבאגים ב-USB"</string> + <string name="adb_active_notification_message" msgid="5617264033476778211">"לוחצים להשבתת ניפוי הבאגים ב-USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"יש ללחוץ על ההתראה כדי להשבית ניפוי באגים ב-USB."</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ניפוי הבאגים האלחוטי מחובר"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"יש ללחוץ כדי להשבית ניפוי באגים אלחוטי"</string> @@ -2089,12 +2129,9 @@ <string name="unpin_target" msgid="3963318576590204447">"ביטול הצמדה"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"ביטול ההצמדה של <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="app_info" msgid="6113278084877079851">"פרטי האפליקציה"</string> - <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) --> - <skip /> - <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) --> - <skip /> - <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) --> - <skip /> + <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"יעדים לשיתוף ישיר"</string> + <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"הצעות לאפליקציות"</string> + <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"רשימת האפליקציות"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"תהליך ההדגמה מתחיל…"</string> <string name="demo_restarting_message" msgid="1160053183701746766">"מתבצע איפוס של המכשיר…"</string> @@ -2251,14 +2288,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"לחצן אמצעי ב-Dpad"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"חלונית ההגדרות של סוג הקליק האוטומטי"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"לחיצה שמאלית"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"לחיצה ימנית"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"לחיצה כפולה"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"גרירה"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"גלילה"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"השהיה"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"מיקום"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string> @@ -2535,12 +2568,8 @@ <string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"מפות"</string> <string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"אפליקציות"</string> <string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"טביעות האצבע שלך נשחקו ואי אפשר לזהות אותן. צריך להגדיר \'פתיחה בטביעת אצבע\' מחדש."</string> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) --> - <skip /> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) --> - <skip /> + <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"התקן ה-USB מחובר כשהמכשיר נעול"</string> + <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"התקן ה-USB מחובר כשמערכת Android נעולה. כדי להשתמש בהתקן ה-USB, קודם צריך לבטל את הנעילה של Android ואז לחבר את ההתקן מחדש."</string> + <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"זוהתה פעילות חשודה בהתקן USB"</string> + <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"האות עם הנתונים מהתקן ה-USB הושבת."</string> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index ad770aaae3ac..7e37dffdff69 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"バイタルサインに関するセンサーデータへのアクセス"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"通知"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"通知を表示"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ウィンドウコンテンツの取得"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ユーザーがアクセスしているウィンドウのコンテンツを検査します。"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"タッチガイドの有効化"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"写真コレクションの変更をアプリに許可します。"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"メディア コレクションの位置情報の読み取り"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"メディア コレクションの位置情報の読み取りをアプリに許可します。"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"生体認証の使用"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"生体認証または画面ロックの使用"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"本人確認"</string> @@ -1432,7 +1472,7 @@ <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"アナログのオーディオ アクセサリーを検出"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"接続したデバイスはこのスマートフォンと互換性がありません。タップすると、詳細を確認できます。"</string> <string name="adb_active_notification_title" msgid="408390247354560331">"USB デバッグが接続されました"</string> - <string name="adb_active_notification_message" msgid="5617264033476778211">"無効にするにはここをタップしてください"</string> + <string name="adb_active_notification_message" msgid="5617264033476778211">"無効にするにはタップしてください"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB デバッグを無効にする場合に選択します。"</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ワイヤレス デバッグが接続されました"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"無効にするにはここをタップしてください"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 481c422ae22c..5ecf5b71638d 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"თქვენი სასიცოცხლო ფუნქციების შესახებ სენსორის მონაცემებზე წვდომა"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"შეტყობინებები"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"შეტყობინებების ჩვენება"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ფანჯრის კონტენტის მოძიება"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"იმ ფანჯრის კონტენტის შემოწმება, რომელშიც მუშაობთ."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"„შეხებით აღმოჩენის“ ჩართვა"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"აპი შეძლებს თქვენი ფოტოკოლექციის შეცვლას."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"მდებარეობების გაცნობა თქვენი მედიაკოლექციიდან"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"აპი შეძლებს მდებარეობების გაცნობას თქვენი მედიაკოლექციიდან."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"გამოიყენეთ ბიომეტრიული სისტემა"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"გამოიყენეთ ბიომეტრიული სისტემა ან ეკრანის დაბლოკვა"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"დაადასტურეთ ვინაობა"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 70412bed6215..98addd075a12 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"ағза күйінің көрсеткіштері туралы сенсор деректеріне қатынасу"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Хабарландырулар"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"хабарландыруларды көрсету"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Терезе контентін оқып отыру"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Ашық тұрған терезе контентін тексеру."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Түртілген элементтерді дыбыстау функциясын қосу"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Қолданбаға суреттер жинағын өзгертуге мүмкіндік береді."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"медиамазмұн жинағынан геодеректерді оқу"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Қолданбаға медиамазмұн жинағынан геодеректерді оқуға мүмкіндік береді."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Биометриканы пайдалану"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометриканы немесе экран құлпын пайдалану"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Cіз екеніңізді растаңыз"</string> @@ -1409,7 +1449,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Жаңа SIM салынды"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Оны орнату үшін түртіңіз"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Уақыт белдеуі өзгертілді"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Қазір <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) уақыт белдеуіндесіз."</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Қазір <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) белдеуіндесіз."</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Уақытты реттеу"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Мезгілін реттеу"</string> <string name="date_time_set" msgid="4603445265164486816">"Орнату"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Ортаңғы Dpad түймесі"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Автоматты басу түрі параметрлері панелі"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Сол жағын басу"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Тінтуірдің оң жақ түймесін басу"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Екі рет басу"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Сүйреу"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Айналдыру"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Кідірту"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Орналастыру"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index fdd522bd0ede..7d0f7785366d 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"ចូលដំណើរការទិន្នន័យឧបករណ៍ចាប់សញ្ញាអំពីស្ថានភាពសុខភាពរបស់អ្នក"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"ការជូនដំណឹង"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"បង្ហាញការជូនដំណឹង"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ទាញយកខ្លឹមសារវិនដូ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ពិនិត្យខ្លឹមសារវិនដូដែលអ្នកកំពុងធ្វើអន្តរកម្មជាមួយ។"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"បើកការរកមើលដោយប៉ះ"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"អនុញ្ញាតឱ្យកម្មវិធីកែប្រែបណ្ដុំរូបថតរបស់អ្នក។"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"អានទីតាំងពីបណ្ដុំមេឌៀរបស់អ្នក"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"អនុញ្ញាតឱ្យកម្មវិធីអានទីតាំងពីបណ្ដុំមេឌៀរបស់អ្នក។"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ប្រើជីវមាត្រ"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ប្រើជីវមាត្រ ឬការចាក់សោអេក្រង់"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ផ្ទៀងផ្ទាត់ថាជាអ្នក"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 887938cce097..e3caae5745f1 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"ನಿಮ್ಮ ಮುಖ್ಯ ಲಕ್ಷಣಗಳ ಕುರಿತು ಸೆನ್ಸಾರ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಿ"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"ನೋಟಿಫಿಕೇಶನ್ಗಳು"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸಿ"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ವಿಂಡೋ ವಿಷಯವನ್ನು ಹಿಂಪಡೆಯುತ್ತದೆ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ನೀವು ಸಂವಹನ ನಡೆಸುತ್ತಿರುವ ವಿಂಡೋದ ಕಂಟೆಂಟ್ ಅನ್ನು ಪರೀಕ್ಷಿಸಿ."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"ಸ್ಪರ್ಶ-ಎಕ್ಸ್ಪ್ಲೋರ್ ಆನ್ ಮಾಡುತ್ತದೆ"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ನಿಮ್ಮ ಫೋಟೋ ಸಂಗ್ರಹಣೆಯನ್ನು ಮಾರ್ಪಡಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಿ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ನಿಮ್ಮ ಮೀಡಿಯಾ ಸಂಗ್ರಹಣೆಯಿಂದ ಸ್ಥಳಗಳನ್ನು ಓದಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ಬಯೋಮೆಟ್ರಿಕ್ಸ್ ಬಳಸಿ"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ಬಯೋಮೆಟ್ರಿಕ್ಸ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ಇದು ನೀವೇ ಎಂದು ಪರಿಶೀಲಿಸಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index fc392711bd57..ffbe631f754e 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"생체 신호에 관한 센서 데이터에 액세스"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"알림"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"알림 표시"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"창 콘텐츠 가져오기"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"상호작용 중인 창의 콘텐츠를 검사합니다."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"터치하여 탐색 사용"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"앱에서 사진 컬렉션을 수정하도록 허용합니다."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"미디어 컬렉션에서 위치 읽기"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"앱에서 미디어 컬렉션의 위치를 읽도록 허용합니다."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"생체 인식 사용"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"생체 인식 또는 화면 잠금을 사용"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"본인 확인"</string> @@ -1027,7 +1067,7 @@ <string name="lockscreen_transport_stop_description" msgid="1449552232598355348">"중지"</string> <string name="lockscreen_transport_rew_description" msgid="7680106856221622779">"되감기"</string> <string name="lockscreen_transport_ffw_description" msgid="4763794746640196772">"빨리 감기"</string> - <string name="emergency_calls_only" msgid="3057351206678279851">"긴급 통화만 허용"</string> + <string name="emergency_calls_only" msgid="3057351206678279851">"긴급 전화만 허용"</string> <string name="lockscreen_network_locked_message" msgid="2814046965899249635">"네트워크 잠김"</string> <string name="lockscreen_sim_puk_locked_message" msgid="2867953953604224166">"SIM이 PUK 잠김 상태입니다."</string> <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"사용자 가이드를 참조하거나 고객지원팀에 문의하세요."</string> @@ -1572,7 +1612,7 @@ <string name="vpn_lockdown_config" msgid="8331697329868252169">"네트워크 또는 VPN 설정 변경"</string> <string name="upload_file" msgid="8651942222301634271">"파일 선택"</string> <string name="no_file_chosen" msgid="4146295695162318057">"파일을 선택하지 않았습니다."</string> - <string name="reset" msgid="3865826612628171429">"초기화"</string> + <string name="reset" msgid="3865826612628171429">"재설정"</string> <string name="submit" msgid="862795280643405865">"제출"</string> <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"운전 앱 실행 중"</string> <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"운전 앱을 종료하려면 탭하세요."</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"방향 패드 가운데"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"자동 클릭 유형 설정 패널"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"왼쪽 클릭"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"오른쪽 클릭"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"더블클릭"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"드래그"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"스크롤"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"일시중지"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"위치"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index f8c0022f0f31..5f19cf7c99f0 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"организмдин абалына көз салган сенсордун дайындарына мүмкүнчүлүк алуу"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Билдирмелер"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"билдирмелерди көрсөтүү"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Терезедеги нерселерди алып туруу"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Учурда ачылып турган терезедеги маалыматты талдайт."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"\"Сыйпалап изилдөө\" мүмкүнчүлүгүн иштетет"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Колдонмого сүрөт жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа жыйнагыңыз сакталган жерлерди окуу"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Биометрикалык параметрлерди колдонуу"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометрикалык жөндөөнү же экрандын кулпусун колдонуу"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Өзүңүздү ырастаңыз"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad\'дын ортоңку баскычы"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Авточыкылдатуу түрүнүн параметрлеринин панели"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Сол баскычын чыкылдатуу"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Оң баскычын чыкылдатуу"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Эки жолу чыкылдатуу"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Сүйрөө"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Сыдыруу"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Тындыруу"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Орду"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 429f3f79cf64..fa1ff2b6a55e 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"ເຂົ້າຫາຂໍ້ມູນເຊັນເຊີກ່ຽວກັບສັນຍານຊີບຂອງທ່ານ"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"ການແຈ້ງເຕືອນ"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"ສະແດງການແຈ້ງເຕືອນ"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ດຶງຂໍ້ມູນເນື້ອຫາໃນໜ້າຈໍ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ກວດກາເນື້ອຫາຂອງໜ້າຈໍທີ່ທ່ານກຳລັງມີປະຕິສຳພັນນຳ."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"ເປີດໃຊ້ \"ການສຳຫຼວດໂດຍສຳຜັດ\""</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ອະນຸຍາດໃຫ້ແອັບແກ້ໄຂຄໍເລັກຊັນຮູບຂອງທ່ານ."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ອະນຸຍາດໃຫ້ແອັບອ່ານສະຖານທີ່ຈາກຄໍເລັກຊັນມີເດຍຂອງທ່ານ."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ໃຊ້ລະບົບຊີວະມິຕິ"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ໃຊ້ລະບົບຊີວະມິຕິ ຫຼື ການລັອກໜ້າຈໍ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ຢັ້ງຢືນວ່າແມ່ນທ່ານ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 3ca681bffc63..b9303fa9d68e 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -355,6 +355,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"pasiekti jutiklių duomenis apie gyvybinius ženklus"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Pranešimai"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"rodyti pranešimus"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Gauti lango turinį"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Tikrinti lango, su kuriuo sąveikaujate, turinį."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Įjungti „Naršyti paliečiant“"</string> @@ -650,6 +658,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Programai leidžiama keisti nuotraukų kolekciją."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"skaityti vietoves iš medijos kolekcijos"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Programai leidžiama skaityti vietoves iš medijos kolekcijos."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Naudoti biometrinius duomenis"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Naudoti biometrinius duomenis arba ekrano užraktą"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Patvirtinkite, kad tai jūs"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 1e7ffd145eac..3a1df4b50b12 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"piekļūt sensoru datiem par jūsu veselības rādījumiem"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Paziņojumi"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"rādīt paziņojumus"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Izgūt loga saturu."</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Skatīt tā loga saturu, ar kuru mijiedarbojaties."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Aktivizēt funkciju “Pārlūkot pieskaroties”."</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ļauj lietotnei pārveidot jūsu fotoattēlu kolekciju."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"Lasīt atrašanās vietas no jūsu multivides kolekcijas"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Ļauj lietotnei lasīt atrašanās vietas no jūsu multivides kolekcijas."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrijas izmantošana"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrijas vai ekrāna bloķēšanas izmantošana"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Apstipriniet, ka tas esat jūs"</string> @@ -2248,14 +2288,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Virzienu slēdzis — centrs"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Automātiskās klikšķināšanas veida iestatījumu panelis"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Noklikšķināt ar peles kreiso pogu"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Noklikšķināt ar peles labo pogu"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Veikt dubultklikšķi"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Vilkt"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Ritināt"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pārtraukt"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozīcija"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index c1a7c1dc5739..c6d51c7f7d18 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"пристапува до податоците од сензорите за виталните функции"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Известувања"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"да прикажува известувања"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"да ги вчитува содржините од прозорците"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"да ги проверува содржините од прозорецот што го користите"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"да вклучи „Истражувај со допир“"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Дозволува апликацијата да ја менува вашата збирка на фотографии."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"да чита локации од вашата збирка на аудиовизуелни содржини"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Дозволува апликацијата да чита локации од вашата збирка на аудиовизуелни содржини."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Користи биометрика"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Користи биометрика или заклучен екран"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Потврдете дека сте вие"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Навигациско копче за средина"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Табла со поставки за вид автоматско кликнување"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Кликни со лево копче"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Кликнување со десно копче"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Кликнување двапати"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Повлекување"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Лизгање"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Паузирај"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Позиционирај"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 5c31433e9456..17fa98b2d372 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"നിങ്ങളുടെ ജീവാധാര ലക്ഷണങ്ങളെ കുറിച്ചുള്ള സെൻസർ വിവരങ്ങൾ ആക്സസ് ചെയ്യുക"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"അറിയിപ്പുകൾ"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"അറിയിപ്പുകൾ കാണിക്കുക"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"വിൻഡോ ഉള്ളടക്കം വീണ്ടെടുക്കുക"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"നിങ്ങൾ സംവദിക്കുന്ന ഒരു വിൻഡോയുടെ ഉള്ളടക്കം പരിശോധിക്കുക."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"സ്പർശനം വഴി പര്യവേക്ഷണം ചെയ്യുക, ഓണാക്കുക"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"നിങ്ങളുടെ ഫോട്ടോ ശേഖരം പരിഷ്ക്കരിക്കുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുക"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"നിങ്ങളുടെ മീഡിയ ശേഖരത്തിൽ നിന്നും ലൊക്കേഷനുകൾ റീഡ് ചെയ്യുന്നതിന് ആപ്പിനെ അനുവദിക്കുന്നു."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ബയോമെട്രിക്സ് ഉപയോഗിക്കുക"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ബയോമെട്രിക്സ് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ഇത് നിങ്ങളാണെന്ന് പരിശോധിച്ചുറപ്പിക്കുക"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 24637fa0b323..48b2aa88ea49 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"таны биеийн байдлын талаарх мэдрэгч бүхий өгөгдөлд нэвтрэх"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Мэдэгдэл"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"мэдэгдэл харуулах"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Цонхны агуулгыг авах"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Таны харилцан үйлчлэх цонхны контентоос шалгах."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Хүрэлтээр сонсохыг асаах"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Таны зургийн цуглуулгыг тохируулах зөвшөөрлийг аппад олгодог."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа цуглуулгаасаа байршлыг унших"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Таны медиа цуглуулгаас байршлыг унших зөвшөөрлийг аппад олгодог."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Биометр ашиглах"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Биометр эсвэл дэлгэцийн түгжээ ашиглах"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Өөрийгөө мөн гэдгийг баталгаажуулаарай"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad гол"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Автомат товшилтын төрлийн тохиргооны түр зуурын самбар"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Зүүн талыг товших"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Баруун талыг товших"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"2 товших"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Чирэх"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Гүйлгэх"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Түр зогсоох"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Байрлал"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 0717eb976261..03400f2db1e8 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"आपल्या महत्त्वाच्या मापनांविषयी सेन्सर डेटा अॅक्सेस करा"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"सूचना"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"सूचना दाखवा"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विंडोमधील आशय पुन्हा मिळवा"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"तुम्ही वापरत असलेल्या विंडोमधील आशय तपासा."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"स्पर्श करून अन्वेषण सुरू करा"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ॲपला तुमच्या फोटो संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"तुमच्या मीडिया संग्रहातून स्थाने वाचा"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ॲपला तुमच्या मीडिया संग्रहामध्येील स्थाने वाचण्यासाठी अनुमती देते."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"बायोमेट्रिक वापरा"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"बायोमेट्रिक किंवा स्क्रीन लॉक वापरा"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"हे तुम्हीच आहात याची पडताळणी करा"</string> @@ -1344,13 +1384,13 @@ <string name="volume_call" msgid="7625321655265747433">"कॉल-मधील व्हॉल्यूम"</string> <string name="volume_bluetooth_call" msgid="2930204618610115061">"ब्लूटूथ कॉल-मधील व्हॉल्यूम"</string> <string name="volume_alarm" msgid="4486241060751798448">"अलार्म व्हॉल्यूम"</string> - <string name="volume_notification" msgid="6864412249031660057">"सूचना व्हॉल्यूम"</string> + <string name="volume_notification" msgid="6864412249031660057">"नोटिफिकेशन व्हॉल्यूम"</string> <string name="volume_unknown" msgid="4041914008166576293">"व्हॉल्यूम"</string> <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"ब्लूटूथ व्हॉल्यूम"</string> <string name="volume_icon_description_ringer" msgid="2187800636867423459">"रिंगटोन व्हॉल्यूम"</string> <string name="volume_icon_description_incall" msgid="4491255105381227919">"कॉल व्हॉल्यूम"</string> <string name="volume_icon_description_media" msgid="4997633254078171233">"मीडिया व्हॉल्यूम"</string> - <string name="volume_icon_description_notification" msgid="579091344110747279">"सूचना व्हॉल्यूम"</string> + <string name="volume_icon_description_notification" msgid="579091344110747279">"नोटिफिकेशन व्हॉल्यूम"</string> <string name="ringtone_default" msgid="9118299121288174597">"डीफॉल्ट रिंगटोन"</string> <string name="ringtone_default_with_actual" msgid="2709686194556159773">"डीफॉल्ट (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> <string name="ringtone_silent" msgid="397111123930141876">"काहीही नाही"</string> @@ -2228,7 +2268,7 @@ <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"होम"</string> <string name="accessibility_system_action_back_label" msgid="4205361367345537608">"मागे जा"</string> <string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"अलीकडील ॲप्स"</string> - <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"सूचना"</string> + <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"नोटिफिकेशन"</string> <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"क्विक सेटिंग्ज"</string> <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"पॉवर डायलॉग"</string> <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करा"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 5cac65d3077c..889324c15a15 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"akses data penderia tentang tanda vital anda"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Pemberitahuan"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"tunjukkan pemberitahuan"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Dapatkan kembali kandungan tetingkap"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Periksa kandungan tetingkap yang berinteraksi dengan anda."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Hidupkan Teroka melalui Sentuhan"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Membenarkan apl mengubah suai koleksi foto anda."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"baca lokasi daripada koleksi media anda"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Membenarkan apl membaca lokasi daripada koleksi media anda."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gunakan biometrik"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gunakan biometrik atau kunci skrin"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Sahkan diri anda"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 10bcd1b75d9c..67f084130f89 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"သင်၏အရေးကြီးသော ကျန်းမာရေးလက္ခဏာဆိုင်ရာ အာရုံခံကိရိယာဒေတာကို ရယူရန်"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"အကြောင်းကြားချက်များ"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"အကြောင်းကြားချက်များ ပြနိုင်သည်"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ဝင်းဒိုးတွင် ပါရှိသည်များကို ပြန်လည်ရယူရန်"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"သင်အသုံးပြုနေသော ဝင်းဒိုးတွင် ပါရှိသည်များကို ကြည့်ရှုစစ်ဆေးသည်။"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"တို့ထိခြင်းဖြင့် ရှာဖွေမှုကို ဖွင့်ရန်"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"အက်ပ်အား သင့်ဓာတ်ပုံစုစည်းမှုကို ပြုပြင်ခွင့်ပေးသည်။"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခြင်း"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"အက်ပ်အား သင့်မီဒီယာစုစည်းမှုမှ တည်နေရာများကို ဖတ်ခွင့်ပေးသည်။"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ဇီဝမက်ထရစ်အချက်အလက်များ သုံးခြင်း"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ဇီဝမက်ထရစ်အချက်အလက်များ (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"သင်ဖြစ်ကြောင်း အတည်ပြုပါ"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad အလယ်"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"အော်တိုနှိပ်ခြင်း အမျိုးအစား ဆက်တင်အကန့်"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ဘယ်ကလစ်"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"ညာဘက်ခလုတ်ကို နှိပ်ရန်"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"နှစ်ချက်နှိပ်ရန်"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ဖိဆွဲရန်"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"လှိမ့်ရန်"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ခဏရပ်ရန်"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"နေရာ"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string> @@ -2518,7 +2554,7 @@ <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"စနစ်ထည့်သွင်းရန်"</string> <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"ယခုမလုပ်ပါ"</string> <string name="bg_user_sound_notification_title_alarm" msgid="5251678483393143527">"<xliff:g id="USER_NAME">%s</xliff:g> အတွက် နှိုးစက်"</string> - <string name="bg_user_sound_notification_button_switch_user" msgid="3091969648572788946">"အသုံးပြုသူ ပြောင်းရန်"</string> + <string name="bg_user_sound_notification_button_switch_user" msgid="3091969648572788946">"အသုံးပြုသူပြောင်းရန်"</string> <string name="bg_user_sound_notification_button_mute" msgid="4942158515665615243">"အသံပိတ်ရန်"</string> <string name="bg_user_sound_notification_message" msgid="8613881975316976673">"အသံပိတ်ရန် တို့ပါ"</string> <string name="keyboard_shortcut_group_applications_browser" msgid="6535007304687100909">"ဘရောင်ဇာ"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 800f118baea5..44458bafab9b 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"få tilgang til sensordata om de vitale tegnene dine"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Varsler"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"vise varsler"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"hente innhold i vinduer"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Appen analyserer innholdet i vinduer du samhandler med."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"slå på berøringsutforsking"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Lar appen gjøre endringer i bildesamlingen din."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lese posisjoner fra mediesamlingen din"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Lar appen lese posisjoner fra mediesamlingen din."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Bruk biometri"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Bruk biometri eller skjermlås"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Bekreft at det er deg"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Midt på styrepilene"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Innstillingspanel for type autoklikk"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Venstreklikk"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Høyreklikk"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dobbeltklikk"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Dra"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Rull"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sett på pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Plassér"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index ce0c67ebd8a2..2591a154a78c 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"तपाईंको महत्त्वपूर्ण संकेत बारे सेन्सर डेटा पहुँच गर्नुहोस्"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"नोटिफिकेसनहरू"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"सूचनाहरू देखाउनुहोस्"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विन्डो सामग्रीको पुनःबहाली गर्नुहोस्।"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"तपाईँको अन्तरक्रिया भइरहेको विन्डोको सामग्रीको निरीक्षण गर्नुहोस्।"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"छोएर गरिने खोजलाई सुचारु गर्नुहोस्"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"यसले एपलाई तपाईंको तस्बिरको सङ्ग्रह परिमार्जन गर्न दिन्छ।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"आफ्नो मिडियाको सङ्ग्रहका स्थानहरू पढ्नुहोस्"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"यसले एपलाई तपाईंको मिडिया सङ्ग्रहका स्थानहरू पढ्न दिन्छ।"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"बायोमेट्रिक्स प्रयोग गर्नुहोस्"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"बायोमेट्रिक्स वा स्क्रिन लक प्रयोग गर्नुहोस्"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"यो व्यक्ति तपाईं नै हो भन्ने प्रमाणित गर्नुहोस्"</string> @@ -1344,13 +1384,13 @@ <string name="volume_call" msgid="7625321655265747433">"इन-कल भोल्युम"</string> <string name="volume_bluetooth_call" msgid="2930204618610115061">"ब्लुटुथ भित्री-कल मात्रा"</string> <string name="volume_alarm" msgid="4486241060751798448">"आलर्मको भोल्युम"</string> - <string name="volume_notification" msgid="6864412249031660057">"सूचनाको भोल्युम"</string> + <string name="volume_notification" msgid="6864412249031660057">"नोटिफिकेसनको भोल्युम"</string> <string name="volume_unknown" msgid="4041914008166576293">"मात्रा"</string> <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"ब्लुटुथ भोल्युम"</string> <string name="volume_icon_description_ringer" msgid="2187800636867423459">"घन्टिको आवाज मात्रा"</string> <string name="volume_icon_description_incall" msgid="4491255105381227919">"कला मात्रा"</string> <string name="volume_icon_description_media" msgid="4997633254078171233">"मिडियाको भोल्युम"</string> - <string name="volume_icon_description_notification" msgid="579091344110747279">"सूचनाको भोल्युम"</string> + <string name="volume_icon_description_notification" msgid="579091344110747279">"नोटिफिकेसनको भोल्युम"</string> <string name="ringtone_default" msgid="9118299121288174597">"डिफल्ट रिङटोन"</string> <string name="ringtone_default_with_actual" msgid="2709686194556159773">"डिफल्ट (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string> <string name="ringtone_silent" msgid="397111123930141876">"कुनै पनि होइन"</string> @@ -2088,12 +2128,9 @@ <string name="unpin_target" msgid="3963318576590204447">"अनपिन गर्नुहोस्"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> लाई अनपिन गर्नुहोस्"</string> <string name="app_info" msgid="6113278084877079851">"एपका बारे जानकारी"</string> - <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) --> - <skip /> - <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) --> - <skip /> - <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) --> - <skip /> + <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"सामग्री सीधै सेयर गर्नका निम्ति चयन गरिएका व्यक्ति वा समूहहरू"</string> + <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"सिफारिस गरिएका एपहरू"</string> + <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"एपहरूको सूची"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"डेमो सुरु गर्दै…"</string> <string name="demo_restarting_message" msgid="1160053183701746766">"यन्त्रलाई रिसेट गर्दै…"</string> @@ -2250,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad को बिचको बटन"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"अटोक्लिकको प्रकारसम्बन्धी सेटिङको प्यानल"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"बायाँ क्लिक गर्नुहोस्"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"राइट क्लिक गर्नुहोस्"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"डबल क्लिक गर्नुहोस्"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ड्र्याग गर्नुहोस्"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"स्क्रोल गर्नुहोस्"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"पज गर्नुहोस्"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"स्थिति"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string> @@ -2534,12 +2567,8 @@ <string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"नक्सा"</string> <string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"एपहरू"</string> <string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"तपाईंको फिंगरप्रिन्ट अब पहिचान गर्न सकिँदैन। फिंगरप्रिन्ट अनलक फेरि सेटअप गर्नुहोस्।"</string> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) --> - <skip /> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) --> - <skip /> + <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"लक भएपछि USB डिभाइस घुसाइएको छ"</string> + <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android लक भएपछि USB डिभाइस घुसाइएको छ। USB डिभाइस प्रयोग गर्न कृपया सुरुमा Android अनलक गर्नुहोस् र त्यसपछि USB डिभाइस फेरि घुसाउनुहोस्।"</string> + <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"USB सम्बन्धी शङ्कास्पद गतिविधि"</string> + <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB डेटा सिग्नल अफ गरिएको छ।"</string> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 34666415d87a..bbdc1bb09c5f 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"toegang krijgen tot sensorgegevens over je vitale functies"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Meldingen"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"meldingen tonen"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Content van vensters ophalen"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"De content inspecteren van een venster waarmee je interactie hebt."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Verkennen via aanraking aanzetten"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Hiermee sta je de app toe je fotocollectie aan te passen."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"locaties van je mediacollecties bekijken"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Hiermee sta je de app toe locaties van je mediacollectie te bekijken."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrische gegevens gebruiken"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrische gegevens of schermvergrendeling gebruiken"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Je identiteit bevestigen"</string> @@ -1409,7 +1449,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Nieuwe simkaart geplaatst"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Tik om dit in te stellen"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Je tijdzone is gewijzigd"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Je bent nu in <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Je tijdzone is <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Tijd instellen"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Datum instellen"</string> <string name="date_time_set" msgid="4603445265164486816">"Instellen"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 418231f5e9b2..a1b24ebe52ed 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"ଆପଣଙ୍କ ଗୁରୁତପୂର୍ଣ୍ଣ ସଂକେତଗୁଡ଼ିକ ବିଷୟରେ ସେନ୍ସର୍ ଡାଟା ଆକ୍ସେସ୍ କରେ"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଦେଖାନ୍ତୁ"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ୱିଣ୍ଡୋ କଣ୍ଟେଣ୍ଟ ହାସଲ କରନ୍ତୁ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ଆପଣ କାମ କରୁଥିବା ୱିଣ୍ଡୋର କଣ୍ଟେଣ୍ଟକୁ ଯାଞ୍ଚ କରନ୍ତୁ।"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"ସ୍ପର୍ଶ ଦ୍ୱାରା ଏକ୍ସପ୍ଲୋର୍ ଅନ୍ କରନ୍ତୁ"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ଆପଣଙ୍କ ଫଟୋ ସଂଗ୍ରହ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଲୋକେସନ୍ଗୁଡିକୁ ପଢନ୍ତୁ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ଆପଣଙ୍କ ମିଡିଆ ସଂଗ୍ରହ ଠାରୁ ଅବସ୍ଥାନଗୁଡିକୁ ପଢିବାକୁ ଆପ୍ ଅନୁମତି ଦେଇଥାଏ।"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ବାୟୋମେଟ୍ରିକ୍ସ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ବାୟୋମେଟ୍ରିକ୍ସ ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ଏହା ଆପଣ ବୋଲି ଯାଞ୍ଚ କରନ୍ତୁ"</string> @@ -1572,7 +1612,7 @@ <string name="vpn_lockdown_config" msgid="8331697329868252169">"ନେଟ୍ୱର୍କ କିମ୍ବା VPN ସେଟିଙ୍ଗ ବଦଳାନ୍ତୁ"</string> <string name="upload_file" msgid="8651942222301634271">"ଫାଇଲ୍ ଚୟନ କରନ୍ତୁ"</string> <string name="no_file_chosen" msgid="4146295695162318057">"କୌଣସି ଫାଇଲ୍ ଚୟନ କରାଯାଇନାହିଁ"</string> - <string name="reset" msgid="3865826612628171429">"ରିସେଟ୍ କରନ୍ତୁ"</string> + <string name="reset" msgid="3865826612628171429">"ରିସେଟ କରନ୍ତୁ"</string> <string name="submit" msgid="862795280643405865">"ଦାଖଲ କରନ୍ତୁ"</string> <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"ଡ୍ରାଇଭିଙ୍ଗ ଆପ୍ ଚାଲୁଛି"</string> <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"ଡ୍ରାଇଭିଙ୍ଗ ଆପ୍ରୁ ବାହାରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad କେନ୍ଦ୍ର"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ଅଟୋକ୍ଲିକ ପ୍ରକାର ସେଟିଂସ ପେନେଲ"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ବାମ ବଟନ କ୍ଲିକ କରନ୍ତୁ"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"ଡାହାଣ କ୍ଲିକ କରନ୍ତୁ"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"ଦୁଇ ଥର କ୍ଲିକ କରନ୍ତୁ"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"ଡ୍ରାଗ କରନ୍ତୁ"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"ସ୍କ୍ରୋଲ କରନ୍ତୁ"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"ବିରତ କରନ୍ତୁ"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ସ୍ଥିତି"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 26769a637388..70dcd66a2fd7 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"ਆਪਣੇ ਸਰੀਰ ਦੇ ਅਹਿਮ ਚਿੰਨ੍ਹਾਂ ਬਾਰੇ ਸੰਵੇਦਕ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"ਸੂਚਨਾਵਾਂ"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ਵਿੰਡੋ ਸਮੱਗਰੀ ਮੁੜ-ਪ੍ਰਾਪਤ ਕਰਨਾ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ਉਸ ਵਿੰਡੋ ਸਮੱਗਰੀ ਦੀ ਜਾਂਚ ਕਰੋ, ਜਿਸ ਨਾਲ ਤੁਸੀਂ ਅੰਤਰਕਿਰਿਆ ਕਰ ਰਹੇ ਹੋ"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"\'ਸਪੱਰਸ਼ ਰਾਹੀਂ ਪੜਚੋਲ ਕਰੋ\' ਚਾਲੂ ਕਰਨਾ"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਟੋ ਸੰਗ੍ਰਹਿ ਨੂੰ ਸੋਧਣ ਦਿੰਦੀ ਹੈ।"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨਾ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਮੀਡੀਆ ਸੰਗ੍ਰਹਿ ਦੇ ਟਿਕਾਣਿਆਂ ਨੂੰ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ਬਾਇਓਮੈਟ੍ਰਿਕ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ਆਪਣੀ ਪਛਾਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index e091700ed9d0..c92c2bb45480 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -355,6 +355,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"dostęp do danych czujnika podstawowych funkcji życiowych"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Powiadomienia"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"pokazuj powiadomienia"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Pobieranie zawartości okna"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Sprawdzanie zawartości okna, z którego korzystasz."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Włączenie czytania dotykiem"</string> @@ -650,6 +658,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Zezwala aplikacji na modyfikowanie kolekcji zdjęć."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"odczytywanie lokalizacji z kolekcji multimediów"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Zezwala aplikacji na odczytywanie lokalizacji z kolekcji multimediów."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Używaj biometrii"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Używaj biometrii lub blokady ekranu"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potwierdź, że to Ty"</string> @@ -1411,7 +1451,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Włożono nową kartę SIM"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Kliknij, by skonfigurować"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Zmieniła się Twoja strefa czasowa"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Jesteś teraz w strefie <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Twoja aktualna strefa to <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Ustaw godzinę"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Ustaw datę"</string> <string name="date_time_set" msgid="4603445265164486816">"Ustaw"</string> @@ -2249,14 +2289,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad – środek"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel ustawień typu automatycznego kliknięcia"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Kliknięcie lewym przyciskiem"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Kliknięcie prawym przyciskiem"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dwukrotne kliknięcie"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Przeciąganie"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Przewijanie"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Wstrzymaj"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozycja"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 06b43cbd0699..99c4375ec5f9 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acesse dados do sensor sobre seus sinais vitais"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificações"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostrar notificações"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Acessar conteúdo de uma janela"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspeciona o conteúdo de uma janela com a qual você está interagindo."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Ativar Explorar por toque"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que o app modifique sua coleção de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler locais na sua coleção de mídias"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que o app leia os locais na sua coleção de mídias."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar biometria"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometria ou bloqueio de tela"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme que é você"</string> @@ -1970,7 +2010,7 @@ <string name="zen_mode_rule_name_combination" msgid="7174598364351313725">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string> <string name="toolbar_collapse_description" msgid="8009920446193610996">"Recolher"</string> <string name="zen_mode_feature_name" msgid="3785547207263754500">"Não perturbe"</string> - <string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"Tempo de inatividade"</string> + <string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"Intervalo"</string> <string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Durante a semana à noite"</string> <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fim de semana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index f48c3260534a..a45354643bf5 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"aceder a dados do sensor acerca dos seus sinais vitais"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificações"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostrar notificações"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Obter conteúdo da janela"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspecionar o conteúdo de uma janela com a qual está a interagir."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Ativar Explorar Através do Toque"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que a app modifique a sua coleção de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler as localizações a partir da sua coleção de multimédia"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que a app leia as localizações a partir da sua coleção de multimédia."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar a biometria"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar a biometria ou o bloqueio de ecrã"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme a sua identidade"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 06b43cbd0699..99c4375ec5f9 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"acesse dados do sensor sobre seus sinais vitais"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificações"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"mostrar notificações"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Acessar conteúdo de uma janela"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspeciona o conteúdo de uma janela com a qual você está interagindo."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Ativar Explorar por toque"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite que o app modifique sua coleção de fotos."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ler locais na sua coleção de mídias"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite que o app leia os locais na sua coleção de mídias."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Usar biometria"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Usar biometria ou bloqueio de tela"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirme que é você"</string> @@ -1970,7 +2010,7 @@ <string name="zen_mode_rule_name_combination" msgid="7174598364351313725">"<xliff:g id="FIRST">%1$s</xliff:g> / <xliff:g id="REST">%2$s</xliff:g>"</string> <string name="toolbar_collapse_description" msgid="8009920446193610996">"Recolher"</string> <string name="zen_mode_feature_name" msgid="3785547207263754500">"Não perturbe"</string> - <string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"Tempo de inatividade"</string> + <string name="zen_mode_downtime_feature_name" msgid="5886005761431427128">"Intervalo"</string> <string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Durante a semana à noite"</string> <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Fim de semana"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Evento"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 73f532a7d633..28728b5c6a15 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"să acceseze datele de la senzori despre semnele vitale"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificări"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"să afișeze notificări"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"să preia conținutul ferestrei"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspectează conținutul unei ferestre cu care interacționezi."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"să activeze funcția Explorează prin atingere"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite aplicației să-ți modifice colecția de fotografii."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"să citească locațiile din colecția media"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite aplicației să citească locațiile din colecția ta media."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Folosește sistemele biometrice"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Folosește sistemele biometrice sau blocarea ecranului"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmă-ți identitatea"</string> @@ -2248,14 +2288,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad centru"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panoul de setări pentru clicul automat"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Clic stânga"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Clic dreapta"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dublu clic"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Trage"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Derulează"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Întrerupe"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Poziție"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index e0e08072482a..f587a73836e3 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -355,6 +355,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"доступ к данным датчиков о состоянии организма"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Уведомления"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"показ уведомлений"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Получать содержимое окна"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Анализировать содержимое активного окна."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Включать Изучение касанием"</string> @@ -650,6 +658,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Приложение сможет вносить изменения в вашу фотоколлекцию."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"Доступ к геоданным в медиаколлекции"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Приложение получит доступ к геоданным в вашей медиаколлекции."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Использовать биометрию"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Использовать биометрию или блокировку экрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Подтвердите, что это вы"</string> @@ -1014,7 +1054,7 @@ <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Повторите попытку"</string> <string name="lockscreen_storage_locked" msgid="634993789186443380">"Разблок. для доступа ко всем функциям и данным"</string> <string name="faceunlock_multiple_failures" msgid="681991538434031708">"Все попытки войти с помощью фейсконтроля использованы"</string> - <string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"SIM-карта отсутствует"</string> + <string name="lockscreen_missing_sim_message_short" msgid="1229301273156907613">"Нет SIM-карты"</string> <string name="lockscreen_missing_sim_message" product="tablet" msgid="3986843848305639161">"В планшете отсутствует SIM-карта."</string> <string name="lockscreen_missing_sim_message" product="tv" msgid="3903140876952198273">"В устройстве Android TV отсутствует SIM-карта."</string> <string name="lockscreen_missing_sim_message" product="default" msgid="6184187634180854181">"В телефоне отсутствует SIM-карта."</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 45dd5df8f83f..f30a48331cc7 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"ඔබේ ජෛව ලක්ෂණ පිළිබඳ සංවේදක දත්ත වෙත පිවිසෙන්න"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"දැනුම්දීම්"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"දැනුම්දීම් පෙන්වන්න"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"කවුළු අන්න්තර්ගතය ලබාගන්න"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ඔබ අන්තර්ක්රියාකාරී වන කවුළුවේ අන්තර්ගතය පරීක්ෂා කරන්න."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"ස්පර්ශයෙන් ගවේෂණය සක්රිය කරන්න"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ඔබගේ ඡායාරූප එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"ඔබගේ මාධ්ය එකතුවෙන් ස්ථාන කියවන්න"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ඔබගේ මාධ්ය එකතුවෙන් ස්ථාන කියවීමට යෙදුමට ඉඩ දෙයි."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ජෛවමිතික භාවිත කරන්න"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ජෛවමිතික හෝ තිර අගුල භාවිත කරන්න"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"එය ඔබ බව තහවුරු කරන්න"</string> @@ -2088,12 +2128,9 @@ <string name="unpin_target" msgid="3963318576590204447">"ගලවන්න"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> ඇමුණුම ඉවත් කරන්න"</string> <string name="app_info" msgid="6113278084877079851">"යෙදුම් තොරතුරු"</string> - <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) --> - <skip /> - <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) --> - <skip /> - <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) --> - <skip /> + <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"සෘජු බෙදා ගැනීමේ ඉලක්ක"</string> + <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"යෙදුම් යෝජනා"</string> + <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"යෙදුම් ලැයිස්තුව"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"ආදර්ශනය ආරම්භ කරමින්..."</string> <string name="demo_restarting_message" msgid="1160053183701746766">"උපාංගය යළි සකසමින්..."</string> @@ -2250,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad මැද"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ස්වයං ක්ලික් ආකාර සැකසීම් පැනලය"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"වම්පස ක්ලිකය"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"දකුණු ක්ලිකය"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"දෙවරක් ක්ලික් කරන්න"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"අදින්න"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"අනුචලනය කරන්න"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"විරාම කරන්න"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"ස්ථානය"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string> @@ -2534,12 +2567,8 @@ <string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"සිතියම්"</string> <string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"යෙදුම්"</string> <string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"ඔබේ ඇඟිලි සලකුණු තවදුරටත් හඳුනාගත නොහැක. ඇඟිලි සලකුණු අගුළු හැරීම නැවත පිහිටුවන්න."</string> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) --> - <skip /> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) --> - <skip /> + <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"අගුළු දමා ඇති විට USB උපාංගය පේනුගත කර ඇත"</string> + <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"Android අගුළු දමා ඇති විට USB උපාංගය පේනුගත කර ඇත. උපාංගය භාවිතා කිරීමට, පළමුව Android අගුළු හැර, පසුව එය භාවිතා කිරීමට USB උපාංගය නැවත ඇතුළු කරන්න."</string> + <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"සැක සහිත USB ක්රියාකාරකම"</string> + <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"USB දත්ත සංඥාව අබල කර ඇත."</string> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index d67597821b2d..49600ced8654 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -355,6 +355,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"prístup k dátam senzorov vašich životných funkcií"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Upozornenia"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"zobrazovať upozornenia"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Načítať obsah okna"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Môžete preskúmať obsah okna, s ktorým pracujete."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Zapnúť funkciu Preskúmanie dotykom"</string> @@ -650,6 +658,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Umožňuje aplikácii upravovať zbierku fotiek."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"čítať polohy zo zbierky médií"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Umožňuje aplikácii čítať polohy zo zbierky médií."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Použiť biometrické údaje"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Použiť biometrické údaje alebo zámku obrazovky"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potvrďte, že ste to vy"</string> @@ -1433,8 +1473,8 @@ <string name="usb_power_notification_message" msgid="7284765627437897702">"Pripojené zariadenie sa nabíja. Ďalšie možností získate klepnutím."</string> <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Bolo zistené analógové zvukové príslušenstvo"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Pripojené zariadenie nie je kompatibilné s týmto telefónom. Ďalšie informácie zobrazíte klepnutím."</string> - <string name="adb_active_notification_title" msgid="408390247354560331">"Ladenie cez USB je pripojené"</string> - <string name="adb_active_notification_message" msgid="5617264033476778211">"Klepnutím vypnite ladenie cez USB"</string> + <string name="adb_active_notification_title" msgid="408390247354560331">"Ladenie cez USB je zapnuté"</string> + <string name="adb_active_notification_message" msgid="5617264033476778211">"Klepnutím vypnete"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Vyberte, ak chcete zakázať ladenie cez USB."</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Bezdrôtové ladenie je pripojené"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Klepnutím vypnete bezdrôtové ladenie"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 0136f5f8311a..c8dc4eec6c16 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -355,6 +355,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"dostop do podatkov tipala o vaših vitalnih znakih"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Obvestila"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"prikaz obvestil"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Pridobiti vsebino okna"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Preverjanje vsebine okna, ki ga uporabljate."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Vklopiti raziskovanje z dotikom"</string> @@ -650,6 +658,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Aplikaciji omogoča spreminjanje zbirke fotografij."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"branje lokacij v predstavnostni zbirki"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Aplikaciji omogoča branje lokacij v predstavnostni zbirki."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Uporaba biometrike"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Uporaba biometrike ali odklepanja s poverilnico"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Potrdite, da ste res vi"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 37aa8bf8108f..fa3eeae0429f 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"qasu tek të dhënat e sensorëve rreth shenjave të tua jetësore"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Njoftimet"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"shfaq njoftimet"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Të nxjerrë përmbajtjen e dritares"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspekton përmbajtjen e dritares me të cilën po ndërvepron."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Të aktivizojë veçorinë \"Eksploro me prekje\""</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Lejon aplikacionin të modifikojë koleksionin tënd të fotografive."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"lexo vendndodhjet nga koleksioni yt i medias"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Lejon aplikacionin të lexojë vendndodhjet nga koleksioni yt i medias."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Përdor sistemet biometrike"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Përdor sistemet biometrike ose kyçjen e ekranit"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiko që je ti"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Qendra e bllokut të drejtimit"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Paneli i cilësimeve për llojin e klikimit automatik"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Klikimi majtas"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Kliko djathtas"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Kliko dy herë"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Zvarrit"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Lëviz"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Vendos në pauzë"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Pozicioni"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index a4f0e556a7c7..54810231691d 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -354,6 +354,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"приступа подацима сензора о виталним функцијама"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Обавештења"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"приказивање обавештења"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"да преузима садржај прозора"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Проверава садржај прозора са којим остварујете интеракцију."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"да укључи Истраживања додиром"</string> @@ -649,6 +657,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Дозвољава апликацији да мења колекцију слика."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"читање локација из медијске колекције"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Дозвољава апликацији да чита локације из медијске колекције."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Користите биометрију"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Користите биометрију или откључавање екрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Потврдите идентитет"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index e56097f06120..38634d574e03 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"få åtkomst till sensordata om dina vitalparametrar"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Aviseringar"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"visa aviseringar"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Hämta fönsterinnehåll"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Granska innehållet i ett fönster som du interagerar med."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Aktivera Explore by touch"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Tillåter att appen gör ändringar i din fotosamling."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"läsa av platser i din mediesamling"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Tillåter att appen läser av platser i din mediesamling."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Använd biometri"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Använd biometrisk data eller skärmlåset"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifiera din identitet"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Styrkors, mitten"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Inställningspanel för typ av automatiskt klick"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Vänsterklick"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Högerklicka"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Dubbelklicka"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Trycka och dra"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Scrolla"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pausa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Position"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 03a581a362ba..b6eab89286f8 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"fikia data ya kitambuzi kuhusu alama zako muhimu"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Arifa"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"kuonyesha arifa"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Kufikia maudhui ya dirisha"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Kuchunguza maudhui ya dirisha unalotumia."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Kuwasha \'Chunguza kwa Kugusa\'"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Inaruhusu programu kubadilisha mkusanyiko wa picha zako."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"kusoma maeneo kwenye mkusanyiko wa vipengee vyako"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Inaruhusu programu kusoma maeneo kwenye mkusanyiko wa vipengee vyako."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Tumia bayometriki"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Tumia bayometriki au mbinu ya kufunga skrini"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Thibitisha kuwa ni wewe"</string> @@ -1409,7 +1449,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"SIM mpya imewekwa"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Gusa ili uiweke"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Saa za eneo lako zimebadilika"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Sasa unatumia saa za eneo za <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Sasa unatumia <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Weka saa"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Weka tarehe"</string> <string name="date_time_set" msgid="4603445265164486816">"Weka"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Kitufe cha katikati cha Dpad"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Kidirisha cha mipangilio ya aina ya kubofya kiotomatiki"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Bofya kushoto"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Bofya kulia"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Bofya mara mbili"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Buruta"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Sogeza"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Sitisha"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Nafasi"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 16c021e8c807..d48f4a276391 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"உங்கள் உடல் இயக்கம் பற்றி உணர்விகள் கூறும் தகவலைப் பார்க்கலாம்"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"அறிவிப்புகள்"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"அறிவிப்புகளைக் காட்டும்"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"சாளர உள்ளடக்கத்தைப் பெறும்"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"நீங்கள் பணியாற்றிக் கொண்டிருக்கும் சாளரத்தின் உள்ளடக்கத்தைப் பார்க்கலாம்."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"தொடுவதன் மூலம் அறிவதை இயக்கும்"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"உங்களின் படத் தொகுப்பை மாற்ற ஆப்ஸை அனுமதிக்கும்."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"மீடியா தொகுப்பிலிருந்து இடங்களை அறிதல்"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"உங்களின் மீடியா தொகுப்பிலிருந்து இடங்களை அறிந்துகொள்ள ஆப்ஸை அனுமதிக்கும்."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"பயோமெட்ரிக்ஸைப் பயன்படுத்து"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"பயோமெட்ரிக்ஸையோ திரைப் பூட்டையோ பயன்படுத்து"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"நீங்கள்தான் என உறுதிசெய்க"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"மையப் பகுதியைக் காட்டும் பட்டன்"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ஆட்டோ கிளிக் வகை அமைப்புகள் பேனல்"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"இடது கிளிக்"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"வலது கிளிக் செய்யும்"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"இரு கிளிக் செய்யும்"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"இழுக்கும்"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"நகர்த்தும்"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"இடைநிறுத்து"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"நிலை"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index c5656187776e..84e56d2a181e 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాను యాక్సెస్ చేస్తుంది"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"నోటిఫికేషన్లు"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"నోటిఫికేషన్లను చూపండి"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"విండో కంటెంట్ను తిరిగి పొందుతుంది"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"మీరు పరస్పర చర్య చేస్తున్న విండో కంటెంట్ను పరిశీలిస్తుంది."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"తాకడం ద్వారా విశ్లేషణను ఆన్ చేయండి"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"మీ ఫోటో సేకరణను ఎడిట్ చేయడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"మీ మీడియా సేకరణ నుండి లొకేషన్లను చదవండి"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"మీ మీడియా సేకరణ నుండి లొకేషన్లను చదవడానికి యాప్ను అనుమతిస్తుంది."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"బయోమెట్రిక్స్ను ఉపయోగించండి"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"బయోమెట్రిక్స్ను లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ఈ చర్య చేస్తోంది మీరేనని వెరిఫై చేయండి"</string> @@ -887,7 +927,7 @@ <item msgid="6216981255272016212">"అనుకూలం"</item> </string-array> <string-array name="emailAddressTypes"> - <item msgid="7786349763648997741">"ఇల్లు"</item> + <item msgid="7786349763648997741">"హోమ్"</item> <item msgid="435564470865989199">"కార్యాలయం"</item> <item msgid="4199433197875490373">"ఇతరం"</item> <item msgid="3233938986670468328">"అనుకూలం"</item> @@ -1153,7 +1193,7 @@ <string name="year" msgid="5182610307741238982">"సంవత్సరం"</string> <string name="years" msgid="5797714729103773425">"సంవత్సరాలు"</string> <string name="now_string_shortest" msgid="3684914126941650330">"ఇప్పుడు"</string> - <string name="duration_minutes_shortest" msgid="5744379079540806690">"<xliff:g id="COUNT">%d</xliff:g>నిమిషం"</string> + <string name="duration_minutes_shortest" msgid="5744379079540806690">"<xliff:g id="COUNT">%d</xliff:g>ని"</string> <string name="duration_hours_shortest" msgid="1477752094141971675">"<xliff:g id="COUNT">%d</xliff:g>గంట"</string> <string name="duration_days_shortest" msgid="4083124701676227233">"<xliff:g id="COUNT">%d</xliff:g>రోజు"</string> <string name="duration_years_shortest" msgid="483982719231145618">"<xliff:g id="COUNT">%d</xliff:g>సం"</string> @@ -2020,7 +2060,7 @@ <string name="call_notification_screening_text" msgid="8396931408268940208">"ఇన్కమింగ్ కాల్ను స్క్రీన్ చేయండి"</string> <string name="default_notification_channel_label" msgid="3697928973567217330">"వర్గీకరించబడలేదు"</string> <string name="promotional_notification_channel_label" msgid="7414844730492860233">"ప్రమోషన్లు"</string> - <string name="social_notification_channel_label" msgid="106520267132019945">"సామాజికం"</string> + <string name="social_notification_channel_label" msgid="106520267132019945">"సోషల్ మీడియా"</string> <string name="news_notification_channel_label" msgid="4299937455247883311">"వార్తలు"</string> <string name="recs_notification_channel_label" msgid="4945985121418684297">"సిఫార్సులు"</string> <string name="importance_from_user" msgid="2782756722448800447">"మీరు ఈ నోటిఫికేషన్ల ప్రాముఖ్యతను సెట్ చేశారు."</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"DPad మధ్యన"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"ఆటో-క్లిక్ టైప్ సెట్టింగ్ల ప్యానెల్"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"ఎడమ క్లిక్"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"రైట్-క్లిక్"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"డబుల్ క్లిక్"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"లాగండి"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"స్క్రోల్ చేయండి"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"పాజ్ చేయండి"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"స్థానం"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్లో ఉంచబడింది"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index f4a3651bc5b7..e16a28a09964 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"เข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพของคุณ"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"การแจ้งเตือน"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"แสดงการแจ้งเตือน"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"เรียกข้อมูลเนื้อหาของหน้าต่าง"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"ตรวจสอบเนื้อหาของหน้าต่างที่คุณกำลังโต้ตอบอยู่"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"เปิด \"แตะเพื่อสำรวจ\""</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"อนุญาตให้แอปแก้ไขคอลเล็กชันรูปภาพของคุณ"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"อ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"อนุญาตให้แอปอ่านตำแหน่งจากคอลเล็กชันสื่อของคุณ"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"ใช้ข้อมูลไบโอเมตริก"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"ใช้ข้อมูลไบโอเมตริกหรือการล็อกหน้าจอ"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"ยืนยันว่าเป็นตัวคุณ"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 8782970c0aed..98de10643617 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"i-access ang data ng sensor tungkol sa iyong vital signs"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Mga Notification"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"magpakita ng mga notification"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Kunin ang content ng window"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Siyasatin ang nilalaman ng isang window kung saan ka nakikipag-ugnayan."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"I-on ang Explore by Touch"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Pinapayagan ang app na baguhin ang iyong koleksyon ng larawan."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"basahin ang mga lokasyon mula sa iyong koleksyon ng media"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Pinapayagan ang app na basahin ang mga lokasyon mula sa iyong koleksyon ng media."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gumamit ng biometrics"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gumamit ng biometrics o lock ng screen"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"I-verify na ikaw ito"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Center"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Panel ng mga setting ng uri ng autoclick"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Mag-left click"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Mag-right click"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Mag-double click"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"I-drag"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Mag-scroll"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"I-pause"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Posisyon"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 7048a83b24b2..2ec15cac8655 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"hayati belirtilerinizle ilgili sensör verilerine erişme"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Bildirimler"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"bildirimleri göster"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Pencere içeriğini alma"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Etkileşim kurduğunuz pencerenin içeriğini inceler."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Dokunarak Keşfet\'i açma"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Uygulamanın fotoğraf koleksiyonunuzu değiştirmesine izin verir."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"medya koleksiyonunuzdaki konumları okuma"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Uygulamanın medya koleksiyonunuzdaki konumları okumasına izin verir."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biyometri kullan"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biyometri veya ekran kilidi kullan"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Kimliğinizi doğrulayın"</string> @@ -1409,7 +1449,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"Yeni SIM kart takıldı"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Kurmak için dokunun"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"Saat diliminiz değişti"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"Artık <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) saat dilimindesiniz"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>) saat dilimindesiniz"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Saati ayarlayın"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"Tarihi ayarlayın"</string> <string name="date_time_set" msgid="4603445265164486816">"Ayarla"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad Orta"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Otomatik tıklama türü ayarları paneli"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Sol tıklama"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Sağ tıklama"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Çift tıklama"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Sürükleme"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Kaydırma"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Duraklatma"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Konum"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index a36699013b33..9aeee9c85ad1 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -355,6 +355,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"отримувати доступ до інформації датчиків про ваші життєві показники"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Сповіщення"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"показувати сповіщення"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Отримувати вміст вікна"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Перевіряти вміст вікна, з яким ви взаємодієте."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Увімкнути функцію дослідження дотиком"</string> @@ -650,6 +658,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Додаток зможе змінювати вашу колекцію фотографій."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"розпізнавати геодані з колекції медіа-вмісту"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Додаток зможе розпізнавати геодані з вашої колекції медіа-вмісту."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Доступ через біометрію"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Використовувати біометрію або дані для розблокування екрана"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Підтвердьте, що це ви"</string> @@ -2090,12 +2130,9 @@ <string name="unpin_target" msgid="3963318576590204447">"Відкріпити"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"Відкріпити додаток <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="app_info" msgid="6113278084877079851">"Про додатки"</string> - <!-- no translation found for shortcut_group_a11y_title (2992150163811583865) --> - <skip /> - <!-- no translation found for suggested_apps_group_a11y_title (2804876567839501831) --> - <skip /> - <!-- no translation found for all_apps_group_a11y_title (7020352520224108745) --> - <skip /> + <string name="shortcut_group_a11y_title" msgid="2992150163811583865">"Цілі прямого надання доступу"</string> + <string name="suggested_apps_group_a11y_title" msgid="2804876567839501831">"Рекомендовані додатки"</string> + <string name="all_apps_group_a11y_title" msgid="7020352520224108745">"Список додатків"</string> <string name="negative_duration" msgid="1938335096972945232">"-<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"Запуск демонстрації…"</string> <string name="demo_restarting_message" msgid="1160053183701746766">"Скидання налаштувань пристрою…"</string> @@ -2252,14 +2289,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Центральна кнопка панелі керування"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Панель налаштувань типу автоматичного натискання"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Натиснути лівою кнопкою миші"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Натиснути правою кнопкою миші"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Двічі натиснути"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Перетягнути"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Прокрутити"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Призупинити"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Змінити позицію"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string> @@ -2536,12 +2569,8 @@ <string name="keyboard_shortcut_group_applications_maps" msgid="7950000659522589471">"Карти"</string> <string name="keyboard_shortcut_group_applications" msgid="3010389163951364798">"Додатки"</string> <string name="fingerprint_loe_notification_msg" msgid="3927447270148854546">"Ваші відбитки пальців більше не розпізнаються. Налаштуйте розблокування відбитком пальця повторно."</string> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_title (468577168569874967) --> - <skip /> - <!-- no translation found for usb_apm_usb_plugged_in_when_locked_notification_text (6695268246267993166) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_title (3461195995882871461) --> - <skip /> - <!-- no translation found for usb_apm_usb_suspicious_activity_notification_text (6537085605929303187) --> - <skip /> + <string name="usb_apm_usb_plugged_in_when_locked_notification_title" msgid="468577168569874967">"USB-пристрій підключено до заблокованого пристрою"</string> + <string name="usb_apm_usb_plugged_in_when_locked_notification_text" msgid="6695268246267993166">"USB-пристрій підключено, коли пристрій Android заблоковано. Щоб використовувати USB-пристрій, вийміть і знову вставте його після того, як розблокуєте пристрій Android."</string> + <string name="usb_apm_usb_suspicious_activity_notification_title" msgid="3461195995882871461">"Підозрілі дії з USB-пристроєм"</string> + <string name="usb_apm_usb_suspicious_activity_notification_text" msgid="6537085605929303187">"Передавання даних через USB вимкнено."</string> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index b725a126e7cd..f934b87d9f5a 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"اپنی علامات حیات کے متعلق سنسر ڈیٹا تک رسائی حاصل کریں"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"اطلاعات"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"اطلاعات دکھائیں"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"ونڈو مواد بازیافت کرنے کی"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"کسی ایسی ونڈو کے مواد کا معائنہ کریں جس کے ساتھ آپ تعامل کر رہے ہیں۔"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"ٹچ کے ذریعے دریافت کریں کو آن کرنے کی"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"ایپ کو آپ کی تصویر کے مجموعے میں ترمیم کی اجازت دیتا ہے۔"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"اپنی میڈيا کے مجموعے سے مقامات پڑھیں"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"ایپ کو آپ کی میڈيا کے مجموعے سے مقامات پڑھنے کی اجازت دیتا ہے۔"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"بایو میٹرکس استعمال کریں"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"بایو میٹرکس یا اسکرین لاک استعمال کریں"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"توثیق کریں کہ یہ آپ ہیں"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index a83466937016..942be7901bc7 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"organizm holati haqidagi sezgich ma’lumotlariga kirish"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Bildirishnomalar"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"bildirishnomalarni chiqarish"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Oynadagi kontentni o‘qiydi"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Joriy oynadagi kontent mazmunini aniqlaydi."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Teginib o‘rganish xizmatini yoqadi"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ilovaga suratlar to‘plamingizni o‘zgartirishga ruxsat beradi."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"multimedia to‘plamidan joylashuv axborotini o‘qish"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Ilovaga multimedia to‘plamingizdan joylashuv axborotini o‘qishga ruxsat beradi."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biometrik tasdiqlash"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biometrika yoki ekran qulfi"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Oʻzingizni taniting"</string> @@ -1431,11 +1471,11 @@ <string name="usb_power_notification_message" msgid="7284765627437897702">"Ulangan qurilma quvvatlanmoqda. Boshqa parametrlar uchun bosing."</string> <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Analogli audio uskuna aniqlandi"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Biriktirilgan qurilma mazkur telefon bilan mos emas. Batafsil axborot olish uchun bu yerga bosing."</string> - <string name="adb_active_notification_title" msgid="408390247354560331">"USB debagging ulandi"</string> - <string name="adb_active_notification_message" msgid="5617264033476778211">"USB debaggingni uzish uchun bosing"</string> + <string name="adb_active_notification_title" msgid="408390247354560331">"USB debaging ulandi"</string> + <string name="adb_active_notification_message" msgid="5617264033476778211">"Uzish uchun bosing"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB orqali nosozliklarni tuzatishni o‘chirib qo‘yish uchun bosing."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wi-Fi orqali debagging yoqildi"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Wi-Fi orqali debagging uzilishi uchun bosing"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wi-Fi orqali debaging yoqildi"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Wi-Fi orqali debaging uzilishi uchun bosing"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Uni faolsizlantirish uchun bosing."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Xavfsizlik sinovi rejimi yoqildi"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Xavfsizlik sinovi rejimini faolsizlantirish uchun zavod sozlamalariga qaytaring."</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad – markazga"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Avtomatik klik turi sozlamalari paneli"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Chap klik"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Oʻng klik"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Ikki marta bosish"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Tortish"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Aylantirish"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Pauza"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Joylashuvi"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index c07ff1d0e040..947a9b4145a8 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"truy cập dữ liệu cảm biến về dấu hiệu sinh tồn của bạn"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Thông báo"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"hiển thị thông báo"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Truy xuất nội dung cửa sổ"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Kiểm tra nội dung của cửa sổ bạn đang tương tác."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Bật tính năng Khám phá bằng cách chạm"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Cho phép ứng dụng này sửa đổi bộ sưu tập ảnh của bạn."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"đọc vị trí từ bộ sưu tập phương tiện"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Cho phép ứng dụng này đọc vị trí từ bộ sưu tập phương tiện của bạn."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Dùng dữ liệu sinh trắc học"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Dùng dữ liệu sinh trắc học hoặc phương thức khóa màn hình"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Xác minh danh tính của bạn"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Căn giữa bằng bàn phím di chuyển"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Bảng cài đặt loại tự động nhấp"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Nhấp chuột trái"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Nhấp chuột phải"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Nhấp đúp"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Kéo"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Cuộn"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Tạm dừng"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Vị trí"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index c746d3c61e33..46c53eb074ac 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"访问与您的生命体征相关的传感器数据"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"通知"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"显示通知"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"检索窗口内容"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"检测您与之互动的窗口的内容。"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"启用触摸浏览"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"允许该应用修改您的照片收藏。"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"从您的媒体收藏中读取位置信息"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"允许该应用从您的媒体收藏中读取位置信息。"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"使用生物识别"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物识别或屏幕锁定凭据"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"验证是您本人在操作"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"方向键中心"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"自动点击类型设置面板"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"点击鼠标左键"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"右键点击"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"双击"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"拖动"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"滚动"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暂停"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index c6b952c99b50..d013a475539b 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"存取與你生命體徵相關的感應器資料"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"通知"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"顯示通知"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"擷取視窗內容"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"檢查你使用中的視窗內容。"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"開啟「輕觸探索」功能"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"允許應用程式修改你的相片集。"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"讀取媒體集的位置"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"允許應用程式讀取媒體集的位置。"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"使用生物識別"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物識別或螢幕鎖定"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"驗證是你本人"</string> @@ -1409,7 +1449,7 @@ <string name="carrier_app_notification_title" msgid="5815477368072060250">"已插入新的 SIM 卡"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"輕按即可設定"</string> <string name="time_zone_change_notification_title" msgid="5232503069219193218">"你的時區已變更"</string> - <string name="time_zone_change_notification_body" msgid="6135793674904665585">"你現在處於 <xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> + <string name="time_zone_change_notification_body" msgid="6135793674904665585">"目前所在時區為<xliff:g id="TIME_ZONE_DISPLAY_NAME">%1$s</xliff:g> (<xliff:g id="TIME_ZONE_OFFSET">%2$s</xliff:g>)"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"設定時間"</string> <string name="date_picker_dialog_title" msgid="5030520449243071926">"日期設定"</string> <string name="date_time_set" msgid="4603445265164486816">"設定"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"十字鍵中心鍵"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"自動點擊類型設定面板"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"按一下左鍵"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"按一下右鍵"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"連按兩下"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"拖曳"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"捲動"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暫停"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index ca0402a1fe2c..f1c9dcdffe62 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"存取與你生命徵象相關的感應器資料"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"通知"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"顯示通知"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"擷取視窗內容"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"檢查你存取的視窗內容。"</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"啟用輕觸探索功能"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"允許應用程式修改你的相片收藏。"</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"讀取你的媒體收藏的位置資訊"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"允許應用程式讀取你的媒體收藏的位置資訊。"</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"使用生物辨識功能"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"使用生物辨識或螢幕鎖定功能"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"驗證你的身分"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Dpad 置中"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"自動點選類型設定面板"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"按滑鼠左鍵"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"按一下滑鼠右鍵"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"按兩下"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"拖曳"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"捲動"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"暫停"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"位置"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 96d6b57ffb4e..5732cec9af95 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -353,6 +353,14 @@ <string name="permgroupdesc_sensors" msgid="2610631290633747752">"finyelela idatha yesizweli mayelana nezimpawu zakho ezibalulekile"</string> <string name="permgrouplab_notifications" msgid="5472972361980668884">"Izaziso"</string> <string name="permgroupdesc_notifications" msgid="4608679556801506580">"bonisa izaziso"</string> + <!-- no translation found for permgrouplab_xr_tracking (7418994009794287471) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking (6777198859446500821) --> + <skip /> + <!-- no translation found for permgrouplab_xr_tracking_sensitive (1194833982988144536) --> + <skip /> + <!-- no translation found for permgroupdesc_xr_tracking_sensitive (9178027369004805829) --> + <skip /> <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Thola okuqukethwe kwewindi"</string> <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Hlola okuqukethwe kwewindi ohlanganyela nalo."</string> <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"Vula ukuhlola ngokuthinta"</string> @@ -648,6 +656,38 @@ <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Ivumela uhlelo lwakho lokusebenza ukuthi lilungise iqoqo lakho lesithombe."</string> <string name="permlab_mediaLocation" msgid="7368098373378598066">"funda izindawo kusukela kuqoqo lakho lemidiya"</string> <string name="permdesc_mediaLocation" msgid="597912899423578138">"Ivumela uhlelo lokusebenza ukuthi lifunde izindawo kusukela kuqoqo lakho lemidiya."</string> + <!-- no translation found for permlab_eye_tracking_coarse (7989596289790269059) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_coarse (870510233930553355) --> + <skip /> + <!-- no translation found for permlab_eye_tracking_fine (6914457357027049512) --> + <skip /> + <!-- no translation found for permdesc_eye_tracking_fine (5788889152304524730) --> + <skip /> + <!-- no translation found for permlab_face_tracking (2272048395128283324) --> + <skip /> + <!-- no translation found for permdesc_face_tracking (2622783922311211866) --> + <skip /> + <!-- no translation found for permlab_hand_tracking (6478233866595566940) --> + <skip /> + <!-- no translation found for permdesc_hand_tracking (8639715900104966456) --> + <skip /> + <!-- no translation found for permlab_head_tracking (1309731456372087270) --> + <skip /> + <!-- no translation found for permdesc_head_tracking (231597390513699188) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_coarse (6518646430502858641) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_coarse (4508880777646198656) --> + <skip /> + <!-- no translation found for permlab_scene_understanding_fine (409126403264393251) --> + <skip /> + <!-- no translation found for permdesc_scene_understanding_fine (6223368011593524179) --> + <skip /> + <!-- no translation found for permlab_xr_tracking_in_background (7117098718465619023) --> + <skip /> + <!-- no translation found for permdesc_xr_tracking_in_background (939504041387836853) --> + <skip /> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Sebenzisa i-biometrics"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Sebenzisa i-biometrics noma ukukhiya isikrini"</string> <string name="biometric_dialog_default_title" msgid="55026799173208210">"Qinisekisa ukuthi nguwe"</string> @@ -2247,14 +2287,10 @@ <string name="accessibility_system_action_dpad_center_label" msgid="8149791419358224893">"Isikhungo se-Dpad"</string> <string name="accessibility_autoclick_type_settings_panel_title" msgid="7354373370578758696">"Iphaneli yamasethingi ohlobo lokuchofoza ngokuzenzekelayo"</string> <string name="accessibility_autoclick_left_click" msgid="2301793352260551080">"Chofoza kwesokunxele"</string> - <!-- no translation found for accessibility_autoclick_right_click (4353495816526181293) --> - <skip /> - <!-- no translation found for accessibility_autoclick_double_click (2103826849116176478) --> - <skip /> - <!-- no translation found for accessibility_autoclick_drag (1499559489796843224) --> - <skip /> - <!-- no translation found for accessibility_autoclick_scroll (3499385943728726933) --> - <skip /> + <string name="accessibility_autoclick_right_click" msgid="4353495816526181293">"Chofoza ngakwesokudla"</string> + <string name="accessibility_autoclick_double_click" msgid="2103826849116176478">"Chofoza kabili"</string> + <string name="accessibility_autoclick_drag" msgid="1499559489796843224">"Hudula"</string> + <string name="accessibility_autoclick_scroll" msgid="3499385943728726933">"Skrola"</string> <string name="accessibility_autoclick_pause" msgid="3272200156172573568">"Misa"</string> <string name="accessibility_autoclick_position" msgid="2933660969907663545">"Indawo"</string> <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 66111785af4f..d2c993aecb0d 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6934,6 +6934,8 @@ <enum name="line" value="2" /> <!-- Ring shape. --> <enum name="ring" value="3" /> + <!-- ARC shape. --> + <enum name="arc" value="4"/> </attr> <!-- Inner radius of the ring expressed as a ratio of the ring's width. For instance, if innerRadiusRatio=9, then the inner radius equals the ring's width divided by 9. @@ -6966,6 +6968,12 @@ <attr name="opticalInsetRight" /> <!-- Bottom optical inset. --> <attr name="opticalInsetBottom" /> + <!-- Attributes that customize the stroke line cap. @hide --> + <attr name="strokeCap" format="enum"> + <enum name="butt" value="0"/> + <enum name="round" value="1"/> + <enum name="square" value="2"/> + </attr> </declare-styleable> <!-- Used to specify the size of the shape for GradientDrawable. --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 1a311d572e0b..2188469bdf03 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2643,6 +2643,15 @@ <!-- MMS user agent prolfile url --> <string name="config_mms_user_agent_profile_url" translatable="false"></string> + <!-- The default list of possible CMF Names|Style|ColorSource. This array can be + overridden device-specific resources. A wildcard (fallback) must be supplied. + Name - Read from `ro.boot.hardware.color` sysprop. Fallback (*) required. + Styles - frameworks/libs/systemui/monet/src/com/android/systemui/monet/Style.java + Color - `home_wallpaper` (for color extraction) or a hexadecimal int (#FFcc99) --> + <string-array name="theming_defaults"> + <item>*|TONAL_SPOT|home_wallpaper</item> + </string-array> + <!-- National Language Identifier codes for the following two config items. (from 3GPP TS 23.038 V9.1.1 Table 6.2.1.2.4.1): 0 - reserved diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index f2ec56c69374..59ed25a1865f 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -64,6 +64,13 @@ <integer name="auto_data_switch_performance_stability_time_threshold_millis">120000</integer> <java-symbol type="integer" name="auto_data_switch_performance_stability_time_threshold_millis" /> + <!-- Define the bar for switching data back to the default SIM when both SIMs are out of service + in milliseconds. A value of 0 means an immediate switch, otherwise for a negative value, + the threshold defined by auto_data_switch_availability_stability_time_threshold_millis + will be used instead. --> + <integer name="auto_data_switch_availability_switchback_stability_time_threshold_millis">150000</integer> + <java-symbol type="integer" name="auto_data_switch_availability_switchback_stability_time_threshold_millis" /> + <!-- Define the maximum retry times when a validation for switching failed.--> <integer name="auto_data_switch_validation_max_retry">7</integer> <java-symbol type="integer" name="auto_data_switch_validation_max_retry" /> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index e9d87e4b5f5b..9acb2427aaab 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -580,9 +580,6 @@ <dimen name="notification_text_size">14sp</dimen> <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) --> <dimen name="notification_title_text_size">14sp</dimen> - <!-- Size of notification text titles, 2025 redesign version (see TextAppearance.StatusBar.EventContent.Title) --> - <!-- TODO: b/378660052 - When inlining the redesign flag, this should be updated directly in TextAppearance.DeviceDefault.Notification.Title --> - <dimen name="notification_2025_title_text_size">16sp</dimen> <!-- Size of big notification text titles (see TextAppearance.StatusBar.EventContent.BigTitle) --> <dimen name="notification_big_title_text_size">16sp</dimen> <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) --> diff --git a/core/res/res/values/dimens_watch.xml b/core/res/res/values/dimens_watch.xml index 2aae98715973..7462b733b0ae 100644 --- a/core/res/res/values/dimens_watch.xml +++ b/core/res/res/values/dimens_watch.xml @@ -52,7 +52,7 @@ <dimen name="primary_content_alpha_device_default">0.38</dimen> <!-- values for wear material3 progress bar(progress indicator) --> - <item name="progressbar_inner_radius_ratio" format="float" type="dimen">2.12</item> + <item name="progressbar_inner_radius_ratio" format="float" type="dimen">2</item> <dimen name="progressbar_thickness">8dp</dimen> <dimen name="progressbar_elevation">0.1dp</dimen> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index e3137e2e77e3..ac1e841d3143 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -116,14 +116,14 @@ <public name="alternateLauncherIcons"/> <!-- @FlaggedApi(android.content.pm.Flags.FLAG_CHANGE_LAUNCHER_BADGING) --> <public name="alternateLauncherLabels"/> - <!-- @hide Only for device overlay to use this. --> - <public name="pointerIconVectorFill"/> - <!-- @hide Only for device overlay to use this. --> - <public name="pointerIconVectorFillInverse"/> - <!-- @hide Only for device overlay to use this. --> - <public name="pointerIconVectorStroke"/> - <!-- @hide Only for device overlay to use this. --> - <public name="pointerIconVectorStrokeInverse"/> + <!-- @hide Wrongly added here. --> + <public name="removed_pointerIconVectorFill"/> + <!-- @hide Wrongly added here. --> + <public name="removed_pointerIconVectorFillInverse"/> + <!-- @hide Wrongly added here. --> + <public name="removed_pointerIconVectorStroke"/> + <!-- @hide Wrongly added here. --> + <public name="removed_pointerIconVectorStrokeInverse"/> </staging-public-group> <staging-public-group type="id" first-id="0x01b20000"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index c62732d36038..b013ffd41ecb 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -575,7 +575,6 @@ <java-symbol type="dimen" name="notification_text_size" /> <java-symbol type="dimen" name="notification_title_text_size" /> <java-symbol type="dimen" name="notification_subtext_size" /> - <java-symbol type="dimen" name="notification_2025_title_text_size" /> <java-symbol type="dimen" name="notification_top_pad" /> <java-symbol type="dimen" name="notification_top_pad_narrow" /> <java-symbol type="dimen" name="notification_top_pad_large_text" /> @@ -1727,10 +1726,12 @@ <java-symbol type="style" name="PointerIconVectorStyleFillBlue" /> <java-symbol type="style" name="PointerIconVectorStyleFillPurple" /> <java-symbol type="attr" name="pointerIconVectorFill" /> + <java-symbol type="attr" name="pointerIconVectorFillInverse" /> <java-symbol type="style" name="PointerIconVectorStyleStrokeWhite" /> <java-symbol type="style" name="PointerIconVectorStyleStrokeBlack" /> <java-symbol type="style" name="PointerIconVectorStyleStrokeNone" /> <java-symbol type="attr" name="pointerIconVectorStroke" /> + <java-symbol type="attr" name="pointerIconVectorStrokeInverse" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Title" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Info" /> @@ -1742,7 +1743,6 @@ <java-symbol type="id" name="media_route_list" /> <java-symbol type="id" name="media_route_volume_layout" /> <java-symbol type="id" name="media_route_volume_slider" /> - <java-symbol type="id" name="media_route_control_frame" /> <java-symbol type="id" name="media_route_extended_settings_button" /> <java-symbol type="id" name="media_route_progress_bar" /> <java-symbol type="string" name="media_route_chooser_title" /> @@ -3264,6 +3264,7 @@ <java-symbol type="dimen" name="notification_content_margin" /> <java-symbol type="dimen" name="notification_2025_margin" /> <java-symbol type="dimen" name="notification_2025_content_margin_top" /> + <java-symbol type="dimen" name="notification_2025_content_margin_start" /> <java-symbol type="dimen" name="notification_2025_expand_button_horizontal_icon_padding" /> <java-symbol type="dimen" name="notification_2025_expand_button_reduced_end_padding" /> <java-symbol type="dimen" name="notification_progress_margin_horizontal" /> @@ -4705,7 +4706,8 @@ <java-symbol type="dimen" name="conversation_icon_container_top_padding" /> <java-symbol type="dimen" name="conversation_icon_container_top_padding_small_avatar" /> <java-symbol type="layout" name="notification_template_material_conversation" /> - <java-symbol type="layout" name="notification_2025_template_conversation" /> + <java-symbol type="layout" name="notification_2025_template_collapsed_conversation" /> + <java-symbol type="layout" name="notification_2025_template_expanded_conversation" /> <java-symbol type="dimen" name="button_padding_horizontal_material" /> <java-symbol type="dimen" name="button_inset_horizontal_material" /> <java-symbol type="layout" name="conversation_face_pile_layout" /> @@ -5648,6 +5650,8 @@ <java-symbol type="id" name="accessibility_autoclick_pause_button" /> <java-symbol type="id" name="accessibility_autoclick_position_layout" /> <java-symbol type="id" name="accessibility_autoclick_position_button" /> + <java-symbol type="drawable" name="accessibility_autoclick_pause" /> + <java-symbol type="drawable" name="accessibility_autoclick_resume" /> <!-- For HapticFeedbackConstants configurability defined at HapticFeedbackCustomization --> <java-symbol type="string" name="config_hapticFeedbackCustomizationFile" /> @@ -5904,6 +5908,9 @@ <java-symbol type="drawable" name="ic_notification_summarization" /> <java-symbol type="dimen" name="notification_collapsed_height_with_summarization" /> + <!-- Device CMF Theming Settings --> + <java-symbol type="array" name="theming_defaults" /> + <!-- Advanced Protection Service USB feature --> <java-symbol type="string" name="usb_apm_usb_plugged_in_when_locked_notification_title" /> <java-symbol type="string" name="usb_apm_usb_plugged_in_when_locked_notification_text" /> diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index c06ad64cc0f5..4c49ff849d49 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -10,8 +10,8 @@ package { filegroup { name: "FrameworksCoreTests-aidl", srcs: [ - "src/**/I*.aidl", "aidl/**/I*.aidl", + "src/**/I*.aidl", ], visibility: ["//visibility:private"], } @@ -19,13 +19,13 @@ filegroup { filegroup { name: "FrameworksCoreTests-helpers", srcs: [ - "DisabledTestApp/src/**/*.java", - "EnabledTestApp/src/**/*.java", + "AppThatCallsBinderMethods/src/**/*.kt", + "BinderDeathRecipientHelperApp/src/**/*.java", "BinderFrozenStateChangeCallbackTestApp/src/**/*.java", "BinderProxyCountingTestApp/src/**/*.java", "BinderProxyCountingTestService/src/**/*.java", - "BinderDeathRecipientHelperApp/src/**/*.java", - "AppThatCallsBinderMethods/src/**/*.kt", + "DisabledTestApp/src/**/*.java", + "EnabledTestApp/src/**/*.java", ], visibility: ["//visibility:private"], } @@ -45,11 +45,11 @@ android_test { defaults: ["FrameworksCoreTests-resources"], srcs: [ - "src/**/*.java", - "src/**/*.kt", + ":FrameworksCoreTestDoubles-sources", ":FrameworksCoreTests-aidl", ":FrameworksCoreTests-helpers", - ":FrameworksCoreTestDoubles-sources", + "src/**/*.java", + "src/**/*.kt", ], aidl: { @@ -65,74 +65,74 @@ android_test { "-c fa", ], static_libs: [ - "collector-device-lib-platform", - "frameworks-base-testutils", - "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport - "core-tests-support", - "cts-input-lib", + "TestParameterInjector", "android-common", - "frameworks-core-util-lib", - "mockwebserver", - "guava", - "guava-android-testlib", "android.app.usage.flags-aconfig-java", + "android.content.res.flags-aconfig-java", + "android.security.flags-aconfig-java", "android.view.accessibility.flags-aconfig-java", "androidx.core_core", "androidx.core_core-ktx", "androidx.test.core", "androidx.test.espresso.core", "androidx.test.ext.junit", - "androidx.test.runner", "androidx.test.rules", + "androidx.test.runner", + "androidx.test.uiautomator_uiautomator", + "collector-device-lib-platform", + "com.android.text.flags-aconfig-java", + "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport + "core-tests-support", + "cts-input-lib", + "device-time-shell-utils", "flag-junit", + "flag-junit", + "flickerlib-parsers", + "flickerlib-trace_processor_shell", + "frameworks-base-testutils", + "frameworks-core-util-lib", + "guava", + "guava-android-testlib", "junit-params", "kotlin-test", + "mockito-kotlin2", + "mockito-target-extended-minus-junit4", "mockito-target-minus-junit4", - "androidx.test.uiautomator_uiautomator", + "mockwebserver", + "perfetto_trace_java_protos", + "platform-compat-test-rules", "platform-parametric-runner-lib", "platform-test-annotations", - "platform-compat-test-rules", - "truth", "print-test-util-lib", - "testng", + "ravenwood-junit", "servicestests-utils", - "device-time-shell-utils", "testables", - "com.android.text.flags-aconfig-java", - "flag-junit", - "ravenwood-junit", - "perfetto_trace_java_protos", - "flickerlib-parsers", - "flickerlib-trace_processor_shell", - "mockito-target-extended-minus-junit4", - "TestParameterInjector", - "android.content.res.flags-aconfig-java", - "android.security.flags-aconfig-java", - "mockito-kotlin2", + "testng", + "truth", ], libs: [ - "android.test.runner.stubs", - "org.apache.http.legacy.stubs", "android.test.base.stubs", "android.test.mock.stubs", - "framework", + "android.test.runner.stubs", + "android.view.flags-aconfig-java", "ext", + "framework", "framework-res", - "android.view.flags-aconfig-java", + "org.apache.http.legacy.stubs", ], jni_libs: [ + "libAppOpsTest_jni", "libpowermanagertest_jni", "libviewRootImplTest_jni", "libworksourceparceltest_jni", - "libAppOpsTest_jni", ], sdk_version: "core_platform", test_suites: [ - "device-tests", - "device-platinum-tests", "automotive-tests", + "device-platinum-tests", + "device-tests", ], certificate: "platform", @@ -141,21 +141,21 @@ android_test { java_resources: [":FrameworksCoreTests_unit_test_cert_der"], data: [ + ":AppThatCallsBinderMethods", + ":AppThatUsesAppOps", ":BinderDeathRecipientHelperApp1", ":BinderDeathRecipientHelperApp2", - ":com.android.cts.helpers.aosp", ":BinderFrozenStateChangeCallbackTestApp", ":BinderProxyCountingTestApp", ":BinderProxyCountingTestService", - ":AppThatUsesAppOps", - ":AppThatCallsBinderMethods", - ":HelloWorldSdk1", - ":HelloWorldUsingSdk1AndSdk1", - ":HelloWorldUsingSdk1And2", - ":HelloWorldUsingSdkMalformedNegativeVersion", ":CtsStaticSharedLibConsumerApp1", ":CtsStaticSharedLibConsumerApp3", ":CtsStaticSharedLibProviderApp1", + ":HelloWorldSdk1", + ":HelloWorldUsingSdk1And2", + ":HelloWorldUsingSdk1AndSdk1", + ":HelloWorldUsingSdkMalformedNegativeVersion", + ":com.android.cts.helpers.aosp", ], } @@ -170,8 +170,8 @@ android_app { // FrameworksCoreTestsRavenwood references the .aapt.srcjar use_resource_processor: false, libs: [ - "framework-res", "android.test.runner.stubs", + "framework-res", "org.apache.http.legacy.stubs", ], uses_libs: [ @@ -231,16 +231,16 @@ android_library { static_libs: [ "androidx.test.espresso.core", "androidx.test.ext.junit", - "androidx.test.runner", "androidx.test.rules", + "androidx.test.runner", "mockito-target-minus-junit4", "truth", ], libs: [ - "android.test.runner.stubs.system", "android.test.base.stubs.system", "android.test.mock.stubs.system", + "android.test.runner.stubs.system", "framework", "framework-res", ], @@ -249,43 +249,43 @@ android_library { android_ravenwood_test { name: "FrameworksCoreTestsRavenwood", libs: [ - "android.test.runner.stubs.system", "android.test.base.stubs.system", + "android.test.runner.stubs.system", ], static_libs: [ - "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport + "androidx.annotation_annotation", "androidx.core_core", "androidx.core_core-ktx", - "androidx.annotation_annotation", - "androidx.test.rules", "androidx.test.ext.junit", + "androidx.test.rules", "androidx.test.uiautomator_uiautomator", "compatibility-device-util-axt-ravenwood", + "core-test-rules", // for libcore.dalvik.system.CloseGuardSupport "flag-junit", - "platform-test-annotations", - "perfetto_trace_java_protos", "flag-junit", + "perfetto_trace_java_protos", + "platform-test-annotations", "testng", ], srcs: [ "src/android/app/ActivityManagerTest.java", + "src/android/app/PropertyInvalidatedCacheTests.java", "src/android/colormodel/CamTest.java", "src/android/content/ContextTest.java", + "src/android/content/TestComponentCallbacks2.java", "src/android/content/pm/PackageManagerTest.java", "src/android/content/pm/UserInfoTest.java", - "src/android/app/PropertyInvalidatedCacheTests.java", - "src/android/database/CursorWindowTest.java", - "src/android/os/**/*.java", "src/android/content/res/*.java", "src/android/content/res/*.kt", + "src/android/database/CursorWindowTest.java", + "src/android/os/**/*.java", "src/android/telephony/PinResultTest.java", "src/android/util/**/*.java", "src/android/view/DisplayAdjustmentsTests.java", - "src/android/view/DisplayTest.java", "src/android/view/DisplayInfoTest.java", + "src/android/view/DisplayTest.java", "src/com/android/internal/logging/**/*.java", "src/com/android/internal/os/**/*.java", - "src/com/android/internal/util/**/*.java", "src/com/android/internal/power/EnergyConsumerStatsTest.java", "src/com/android/internal/ravenwood/**/*.java", @@ -293,10 +293,12 @@ android_ravenwood_test { // to avoid having a dependency to FrameworksCoreTests. // This way, when updating source files and running this test, we don't need to // rebuild the entire FrameworksCoreTests, which would be slow. - ":FrameworksCoreTests-resonly{.aapt.srcjar}", + "src/com/android/internal/util/**/*.java", + + ":FrameworksCoreTestDoubles-sources", ":FrameworksCoreTests-aidl", ":FrameworksCoreTests-helpers", - ":FrameworksCoreTestDoubles-sources", + ":FrameworksCoreTests-resonly{.aapt.srcjar}", ], exclude_srcs: [ "src/android/content/res/FontScaleConverterActivityTest.java", @@ -320,8 +322,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_annotations: ["android.platform.test.annotations.Presubmit"], } @@ -331,12 +333,12 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ - "com.android.internal.inputmethod", "android.view.inputmethod", + "com.android.internal.inputmethod", ], exclude_annotations: ["androidx.test.filters.FlakyTest"], } @@ -346,8 +348,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.content.ContextTest"], } @@ -357,8 +359,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.app.KeyguardManagerTest"], } @@ -368,8 +370,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.app.PropertyInvalidatedCacheTests"], } @@ -379,12 +381,12 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ - "android.content.ContextTest", "android.content.ComponentCallbacksControllerTest", + "android.content.ContextTest", "android.content.ContextWrapperTest", ], } @@ -394,8 +396,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.database.sqlite.SQLiteRawStatementTest"], } @@ -405,8 +407,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.net"], include_annotations: ["android.platform.test.annotations.Presubmit"], @@ -417,8 +419,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.os.BatteryStatsTests"], exclude_annotations: ["com.android.internal.os.SkipPresubmit"], @@ -429,8 +431,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.os.EnvironmentTest"], } @@ -440,12 +442,12 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ - "com.android.internal.util.FastDataTest", "android.util.CharsetUtilsTest", + "com.android.internal.util.FastDataTest", ], } @@ -454,12 +456,12 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ - "android.util.XmlTest", "android.util.BinaryXmlTest", + "android.util.XmlTest", ], } @@ -468,8 +470,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.util.apk.SourceStampVerifierTest"], } @@ -479,8 +481,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.view.textclassifier"], exclude_annotations: ["androidx.test.filters.FlakyTest"], @@ -491,13 +493,13 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.app."], exclude_filters: [ - "com.android.internal.app.WindowDecorActionBarTest", "com.android.internal.app.IntentForwarderActivityTest", + "com.android.internal.app.WindowDecorActionBarTest", ], } @@ -506,8 +508,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.content."], } @@ -517,8 +519,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.infra."], } @@ -528,8 +530,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.jank"], } @@ -539,16 +541,16 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ - "android.os.BinderProxyTest", "android.os.BinderDeathRecipientTest", "android.os.BinderFrozenStateChangeNotificationTest", "android.os.BinderProxyCountingTest", - "android.os.BinderUncaughtExceptionHandlerTest", + "android.os.BinderProxyTest", "android.os.BinderThreadPriorityTest", + "android.os.BinderUncaughtExceptionHandlerTest", "android.os.BinderWorkSourceTest", "android.os.ParcelNullabilityTest", "android.os.ParcelTest", @@ -562,13 +564,13 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ - "com.android.internal.os.KernelCpuUidClusterTimeReaderTest", - "com.android.internal.os.KernelCpuUidBpfMapReaderTest", "com.android.internal.os.KernelCpuUidActiveTimeReaderTest", + "com.android.internal.os.KernelCpuUidBpfMapReaderTest", + "com.android.internal.os.KernelCpuUidClusterTimeReaderTest", "com.android.internal.os.KernelCpuUidFreqTimeReaderTest", "com.android.internal.os.KernelSingleUidTimeReaderTest", ], @@ -579,8 +581,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.server.power.stats.BstatsCpuTimesValidationTest"], } @@ -590,8 +592,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.security."], include_annotations: ["android.platform.test.annotations.Presubmit"], @@ -602,8 +604,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.util.LatencyTrackerTest"], } @@ -613,8 +615,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.content.ContentCaptureOptionsTest"], } @@ -624,8 +626,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.content.integrity."], } @@ -635,8 +637,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.content.pm."], include_annotations: ["android.platform.test.annotations.Presubmit"], @@ -647,8 +649,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.content.pm."], include_annotations: ["android.platform.test.annotations.Postsubmit"], @@ -659,14 +661,14 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.content.res."], include_annotations: ["android.platform.test.annotations.Presubmit"], exclude_annotations: [ - "androidx.test.filters.FlakyTest", "android.platform.test.annotations.Postsubmit", + "androidx.test.filters.FlakyTest", "org.junit.Ignore", ], } @@ -676,8 +678,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.content.res."], include_annotations: ["android.platform.test.annotations.Postsubmit"], @@ -688,17 +690,17 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ + "android.service.controls", + "android.service.controls.actions", + "android.service.controls.templates", "android.service.euicc", "android.service.notification", "android.service.quicksettings", "android.service.settings.suggestions", - "android.service.controls.templates", - "android.service.controls.actions", - "android.service.controls", ], exclude_annotations: ["org.junit.Ignore"], } @@ -708,8 +710,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.view.contentcapture"], } @@ -719,8 +721,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.view.contentprotection"], } @@ -730,8 +732,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.content."], include_annotations: ["android.platform.test.annotations.Presubmit"], @@ -742,8 +744,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.graphics.drawable.IconTest"], } @@ -753,13 +755,13 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ - "com.android.internal.accessibility", "android.accessibilityservice", "android.view.accessibility", + "com.android.internal.accessibility", ], } @@ -768,8 +770,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.app.usage"], } @@ -779,8 +781,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["com.android.internal.util.FastDataTest"], } @@ -790,8 +792,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: ["android.hardware.input"], } @@ -801,12 +803,12 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ - "android.view.VerifiedMotionEventTest", "android.view.VerifiedKeyEventTest", + "android.view.VerifiedMotionEventTest", ], } @@ -839,8 +841,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_filters: [ "com.android.internal.jank.FrameTrackerTest", @@ -854,8 +856,8 @@ test_module_config { base: "FrameworksCoreTests", test_suites: [ "automotive-tests", - "device-tests", "device-platinum-tests", + "device-tests", ], include_annotations: ["android.platform.test.annotations.PlatinumTest"], } diff --git a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java index 7b41217d6200..ab2e77e57b47 100644 --- a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java +++ b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java @@ -23,6 +23,8 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.fail; +import static org.junit.Assert.assertThrows; + import android.app.backup.BackupRestoreEventLogger.DataTypeResult; import android.os.Parcel; import android.platform.test.annotations.Presubmit; @@ -32,6 +34,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.server.backup.Flags; +import com.google.common.truth.Expect; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -42,6 +46,7 @@ import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Optional; @Presubmit @@ -64,6 +69,9 @@ public class BackupRestoreEventLoggerTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public final Expect expect = Expect.create(); + @Before public void setUp() throws Exception { mHashDigest = MessageDigest.getInstance("SHA-256"); @@ -366,6 +374,32 @@ public class BackupRestoreEventLoggerTest { assertThat(mLogger.getLoggingResults()).isEmpty(); } + @Test + public void testDataTypeResultToString_nullArgs() { + assertThrows(NullPointerException.class, () -> BackupRestoreEventLogger.toString(null)); + } + + @Test + public void testDataTypeResultToString_typeOnly() { + DataTypeResult result = new DataTypeResult("The Type is Bond, James Bond!"); + + expect.withMessage("toString()") + .that(BackupRestoreEventLogger.toString(result)).isEqualTo( + "type=The Type is Bond, James Bond!, successCount=0, failCount=0"); + } + + @Test + public void testDataTypeResultToString_allFields() { + DataTypeResult result = DataTypeResultTest.createDataTypeResult( + "The Type is Bond, James Bond!", /* successCount= */ 42, /* failCount= */ 108, + Map.of("D'OH!", 666, "", 0), new byte[] { 4, 8, 15, 16, 23, 42 }); + + expect.withMessage("toString()") + .that(BackupRestoreEventLogger.toString(result)).isEqualTo( + "type=The Type is Bond, James Bond!, successCount=42, failCount=108, " + + "errors={=0, D'OH!=666}, metadataHash=[4, 8, 15, 16, 23, 42]"); + } + private static DataTypeResult getResultForDataType( BackupRestoreEventLogger logger, String dataType) { Optional<DataTypeResult> result = getResultForDataTypeIfPresent(logger, dataType); diff --git a/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java b/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java new file mode 100644 index 000000000000..cf9e9c6e2f95 --- /dev/null +++ b/core/tests/coretests/src/android/app/backup/DataTypeResultTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.app.backup; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.app.backup.BackupRestoreEventLogger.DataTypeResult; +import android.os.Bundle; +import android.os.Parcel; + +import com.google.common.truth.Expect; + +import org.junit.Rule; +import org.junit.Test; + +import java.util.Map; + +public final class DataTypeResultTest { + + @Rule + public final Expect expect = Expect.create(); + + @Test + public void testGetters_defaultConstructorFields() { + var result = new DataTypeResult("The Type is Bond, James Bond!"); + + expect.withMessage("getDataType()").that(result.getDataType()) + .isEqualTo("The Type is Bond, James Bond!"); + expect.withMessage("getSuccessCount()").that(result.getSuccessCount()).isEqualTo(0); + expect.withMessage("getFailCount()").that(result.getFailCount()).isEqualTo(0); + expect.withMessage("getErrorsCount()").that(result.getErrors()).isEmpty(); + expect.withMessage("getMetadataHash()").that(result.getMetadataHash()).isNull(); + expect.withMessage("describeContents()").that(result.describeContents()).isEqualTo(0); + } + + @Test + public void testGetters_allFields() { + DataTypeResult result = createDataTypeResult("The Type is Bond, James Bond!", + /* successCount= */ 42, /* failCount= */ 108, Map.of("D'OH!", 666), + new byte[] { 4, 8, 15, 16, 23, 42 }); + + expect.withMessage("getDataType()").that(result.getDataType()) + .isEqualTo("The Type is Bond, James Bond!"); + expect.withMessage("getSuccessCount()").that(result.getSuccessCount()).isEqualTo(42); + expect.withMessage("getFailCount()").that(result.getFailCount()).isEqualTo(108); + expect.withMessage("getErrorsCount()").that(result.getErrors()).containsExactly("D'OH!", + 666); + expect.withMessage("getMetadataHash()").that(result.getMetadataHash()).asList() + .containsExactly((byte) 4, (byte) 8, (byte) 15, (byte) 16, (byte) 23, (byte) 42) + .inOrder(); + expect.withMessage("describeContents()").that(result.describeContents()).isEqualTo(0); + } + + @Test + public void testParcelMethods() { + DataTypeResult original = createDataTypeResult("The Type is Bond, James Bond!", + /* successCount= */ 42, /* failCount= */ 108, Map.of("D'OH!", 666), + new byte[] { 4, 8, 15, 16, 23, 42 }); + Parcel parcel = Parcel.obtain(); + try { + original.writeToParcel(parcel, /* flags= */ 0); + + parcel.setDataPosition(0); + var clone = DataTypeResult.CREATOR.createFromParcel(parcel); + assertWithMessage("createFromParcel()").that(clone).isNotNull(); + + expect.withMessage("getDataType()").that(clone.getDataType()) + .isEqualTo(original.getDataType()); + expect.withMessage("getSuccessCount()").that(clone.getSuccessCount()) + .isEqualTo(original.getSuccessCount()); + expect.withMessage("getFailCount()").that(clone.getFailCount()) + .isEqualTo(original.getFailCount()); + expect.withMessage("getErrorsCount()").that(clone.getErrors()) + .containsExactlyEntriesIn(original.getErrors()).inOrder(); + expect.withMessage("getMetadataHash()").that(clone.getMetadataHash()) + .isEqualTo(original.getMetadataHash()); + expect.withMessage("describeContents()").that(clone.describeContents()).isEqualTo(0); + } finally { + parcel.recycle(); + } + } + + static DataTypeResult createDataTypeResult(String dataType, int successCount, int failCount, + Map<String, Integer> errors, byte... metadataHash) { + Parcel parcel = Parcel.obtain(); + try { + parcel.writeString(dataType); + parcel.writeInt(successCount); + parcel.writeInt(failCount); + Bundle errorsBundle = new Bundle(); + errors.entrySet() + .forEach(entry -> errorsBundle.putInt(entry.getKey(), entry.getValue())); + parcel.writeBundle(errorsBundle); + parcel.writeByteArray(metadataHash); + + parcel.setDataPosition(0); + var result = DataTypeResult.CREATOR.createFromParcel(parcel); + assertWithMessage("createFromParcel()").that(result).isNotNull(); + return result; + } finally { + parcel.recycle(); + } + } +} diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java index a02af788d496..2505500411b5 100644 --- a/core/tests/coretests/src/android/content/ContextTest.java +++ b/core/tests/coretests/src/android/content/ContextTest.java @@ -23,6 +23,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -35,17 +36,24 @@ import android.graphics.PixelFormat; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.media.ImageReader; +import android.os.Looper; import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.DisabledOnRavenwood; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.ravenwood.RavenwoodRule; import android.view.Display; +import android.window.WindowTokenClient; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.window.flags.Flags; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -61,6 +69,9 @@ public class ContextTest { @Rule public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Test public void testInstrumentationContext() { // Confirm that we have a valid Context @@ -280,4 +291,44 @@ public class ContextTest { return appContext.createDisplayContext(display) .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */); } + + @Test + @DisabledOnRavenwood(blockedBy = Context.class) + @DisableFlags(Flags.FLAG_TRACK_SYSTEM_UI_CONTEXT_BEFORE_WMS) + public void testSysUiContextRegisterComponentCallbacks_disableFlag() { + Looper.prepare(); + + // Use createSystemActivityThreadForTesting to initialize + // systemUiContext#getApplicationContext. + final Context systemUiContext = ActivityThread.createSystemActivityThreadForTesting() + .getSystemUiContext(); + final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2(); + systemUiContext.registerComponentCallbacks(callbacks); + + final WindowTokenClient windowTokenClient = + (WindowTokenClient) systemUiContext.getWindowContextToken(); + windowTokenClient.onConfigurationChanged(Configuration.EMPTY, DEFAULT_DISPLAY); + + assertWithMessage("ComponentCallbacks should delegate to the app Context " + + "if the flag is disabled.").that(callbacks.mConfiguration).isNull(); + } + + @Test + @DisabledOnRavenwood(blockedBy = Context.class) + @EnableFlags(Flags.FLAG_TRACK_SYSTEM_UI_CONTEXT_BEFORE_WMS) + public void testSysUiContextRegisterComponentCallbacks_enableFlag() { + final Context systemUiContext = ActivityThread.currentActivityThread() + .createSystemUiContextForTesting(DEFAULT_DISPLAY); + final TestComponentCallbacks2 callbacks = new TestComponentCallbacks2(); + final Configuration config = Configuration.EMPTY; + + systemUiContext.registerComponentCallbacks(callbacks); + + final WindowTokenClient windowTokenClient = + (WindowTokenClient) systemUiContext.getWindowContextToken(); + windowTokenClient.onConfigurationChanged(config, DEFAULT_DISPLAY); + + assertWithMessage("ComponentCallbacks should delegate to SystemUiContext " + + "if the flag is enabled.").that(callbacks.mConfiguration).isEqualTo(config); + } } diff --git a/core/tests/coretests/src/android/content/pm/SystemFeaturesCacheTest.java b/core/tests/coretests/src/android/content/pm/SystemFeaturesCacheTest.java index ce4aa42f39b6..8b513cb996b5 100644 --- a/core/tests/coretests/src/android/content/pm/SystemFeaturesCacheTest.java +++ b/core/tests/coretests/src/android/content/pm/SystemFeaturesCacheTest.java @@ -21,12 +21,16 @@ import static android.content.pm.PackageManager.FEATURE_WATCH; import static com.google.common.truth.Truth.assertThat; -import android.os.Parcel; +import static org.junit.Assert.assertThrows; +import static org.junit.Assume.assumeTrue; + import android.util.ArrayMap; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,6 +40,19 @@ public class SystemFeaturesCacheTest { private SystemFeaturesCache mCache; + private SystemFeaturesCache mOriginalSingletonCache; + + @Before + public void setUp() { + mOriginalSingletonCache = SystemFeaturesCache.getInstance(); + } + + @After + public void tearDown() { + SystemFeaturesCache.clearInstance(); + SystemFeaturesCache.setInstance(mOriginalSingletonCache); + } + @Test public void testNoFeatures() throws Exception { SystemFeaturesCache cache = new SystemFeaturesCache(new ArrayMap<String, FeatureInfo>()); @@ -84,29 +101,57 @@ public class SystemFeaturesCacheTest { } @Test - public void testParcel() throws Exception { + public void testGetAndSetFeatureVersions() throws Exception { ArrayMap<String, FeatureInfo> features = new ArrayMap<>(); features.put(FEATURE_WATCH, createFeature(FEATURE_WATCH, 0)); SystemFeaturesCache cache = new SystemFeaturesCache(features); - Parcel parcel = Parcel.obtain(); - SystemFeaturesCache parceledCache; - try { - parcel.writeParcelable(cache, 0); - parcel.setDataPosition(0); - parceledCache = parcel.readParcelable(getClass().getClassLoader()); - } finally { - parcel.recycle(); - } - - assertThat(parceledCache.maybeHasFeature(FEATURE_WATCH, 0)) + assertThat(cache.getSdkFeatureVersions().length) + .isEqualTo(PackageManager.SDK_FEATURE_COUNT); + + SystemFeaturesCache clonedCache = new SystemFeaturesCache(cache.getSdkFeatureVersions()); + assertThat(cache.getSdkFeatureVersions()).isEqualTo(clonedCache.getSdkFeatureVersions()); + + assertThat(clonedCache.maybeHasFeature(FEATURE_WATCH, 0)) .isEqualTo(cache.maybeHasFeature(FEATURE_WATCH, 0)); - assertThat(parceledCache.maybeHasFeature(FEATURE_PICTURE_IN_PICTURE, 0)) + assertThat(clonedCache.maybeHasFeature(FEATURE_PICTURE_IN_PICTURE, 0)) .isEqualTo(cache.maybeHasFeature(FEATURE_PICTURE_IN_PICTURE, 0)); - assertThat(parceledCache.maybeHasFeature("custom.feature", 0)) + assertThat(clonedCache.maybeHasFeature("custom.feature", 0)) .isEqualTo(cache.maybeHasFeature("custom.feature", 0)); } + @Test + public void testInvalidFeatureVersions() throws Exception { + // Raw feature version arrays must match the predefined SDK feature count. + int[] invalidFeatureVersions = new int[PackageManager.SDK_FEATURE_COUNT - 1]; + assertThrows( + IllegalArgumentException.class, + () -> new SystemFeaturesCache(invalidFeatureVersions)); + } + + @Test + public void testSingleton() throws Exception { + ArrayMap<String, FeatureInfo> features = new ArrayMap<>(); + features.put(FEATURE_WATCH, createFeature(FEATURE_WATCH, 0)); + SystemFeaturesCache cache = new SystemFeaturesCache(features); + + SystemFeaturesCache.clearInstance(); + assertThrows(IllegalStateException.class, () -> SystemFeaturesCache.getInstance()); + + SystemFeaturesCache.setInstance(cache); + assertThat(SystemFeaturesCache.getInstance()).isEqualTo(cache); + + assertThrows( + IllegalStateException.class, + () -> SystemFeaturesCache.setInstance(new SystemFeaturesCache(features))); + } + + @Test + public void testSingletonAutomaticallySetWithFeatureEnabled() { + assumeTrue(android.content.pm.Flags.cacheSdkSystemFeatures()); + assertThat(SystemFeaturesCache.getInstance()).isNotNull(); + } + private static FeatureInfo createFeature(String name, int version) { FeatureInfo fi = new FeatureInfo(); fi.name = name; diff --git a/core/tests/coretests/src/android/os/PerfettoTraceTest.java b/core/tests/coretests/src/android/os/PerfettoTraceTest.java index c5c2554c2a67..fb743d2b42ad 100644 --- a/core/tests/coretests/src/android/os/PerfettoTraceTest.java +++ b/core/tests/coretests/src/android/os/PerfettoTraceTest.java @@ -77,6 +77,8 @@ public class PerfettoTraceTest { private static final String TAG = "PerfettoTraceTest"; private static final String FOO = "foo"; private static final String BAR = "bar"; + private static final String TEXT_ABOVE_4K_SIZE = + new String(new char[8192]).replace('\0', 'a'); private static final Category FOO_CATEGORY = new Category(FOO); private static final int MESSAGE = 1234567; @@ -155,41 +157,6 @@ public class PerfettoTraceTest { @Test @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) - public void testDebugAnnotationsWithLambda() throws Exception { - TraceConfig traceConfig = getTraceConfig(FOO); - - PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); - - PerfettoTrace.instant(FOO_CATEGORY, "event").addArg("long_val", 123L).emit(); - - byte[] traceBytes = session.close(); - - Trace trace = Trace.parseFrom(traceBytes); - - boolean hasTrackEvent = false; - boolean hasDebugAnnotations = false; - for (TracePacket packet: trace.getPacketList()) { - TrackEvent event; - if (packet.hasTrackEvent()) { - hasTrackEvent = true; - event = packet.getTrackEvent(); - - if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType()) - && event.getDebugAnnotationsCount() == 1) { - hasDebugAnnotations = true; - - List<DebugAnnotation> annotations = event.getDebugAnnotationsList(); - assertThat(annotations.get(0).getIntValue()).isEqualTo(123L); - } - } - } - - assertThat(hasTrackEvent).isTrue(); - assertThat(hasDebugAnnotations).isTrue(); - } - - @Test - @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) public void testNamedTrack() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); @@ -440,7 +407,6 @@ public class PerfettoTraceTest { boolean hasTrackEvent = false; boolean hasSourceLocation = false; - for (TracePacket packet: trace.getPacketList()) { TrackEvent event; if (packet.hasTrackEvent()) { @@ -467,6 +433,53 @@ public class PerfettoTraceTest { @Test @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) + public void testProtoWithSlowPath() throws Exception { + TraceConfig traceConfig = getTraceConfig(FOO); + + PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray()); + + PerfettoTrace.instant(FOO_CATEGORY, "event_proto") + .beginProto() + .beginNested(33L) + .addField(4L, 2L) + .addField(3, TEXT_ABOVE_4K_SIZE) + .endNested() + .addField(2001, "AIDL::IActivityManager") + .endProto() + .emit(); + + byte[] traceBytes = session.close(); + + Trace trace = Trace.parseFrom(traceBytes); + + boolean hasTrackEvent = false; + boolean hasSourceLocation = false; + for (TracePacket packet: trace.getPacketList()) { + TrackEvent event; + if (packet.hasTrackEvent()) { + hasTrackEvent = true; + event = packet.getTrackEvent(); + + if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType()) + && event.hasSourceLocation()) { + SourceLocation loc = event.getSourceLocation(); + if (TEXT_ABOVE_4K_SIZE.equals(loc.getFunctionName()) + && loc.getLineNumber() == 2) { + hasSourceLocation = true; + } + } + } + + collectInternedData(packet); + } + + assertThat(hasTrackEvent).isTrue(); + assertThat(hasSourceLocation).isTrue(); + assertThat(mCategoryNames).contains(FOO); + } + + @Test + @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2) public void testProtoNested() throws Exception { TraceConfig traceConfig = getTraceConfig(FOO); diff --git a/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java b/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java index d91541fbc1fc..d6426b0313d4 100644 --- a/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java +++ b/core/tests/coretests/src/android/view/AccessibilityInteractionControllerTest.java @@ -25,6 +25,7 @@ import android.app.Instrumentation; import android.app.Service; import android.app.UiAutomation; import android.graphics.Rect; +import android.os.Process; import android.os.SystemClock; import android.text.TextUtils; import android.view.accessibility.AccessibilityEvent; @@ -32,6 +33,7 @@ import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityTestActivity; import android.view.accessibility.AccessibilityWindowInfo; +import android.view.accessibility.IWindowSurfaceInfoCallback; import androidx.test.InstrumentationRegistry; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -47,6 +49,7 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import java.util.List; import java.util.concurrent.TimeoutException; @@ -136,6 +139,20 @@ public class AccessibilityInteractionControllerTest { } } + @Test + public void getWindowSurfaceInfo_shouldCallCallbackWithWindowSurfaceDataFromVri() + throws Exception { + final ViewRootImpl vri = mButton.getRootView().getViewRootImpl(); + IWindowSurfaceInfoCallback callback = Mockito.mock(IWindowSurfaceInfoCallback.class); + + sInstrumentation.runOnMainSync(() -> + mAccessibilityInteractionController.getWindowSurfaceInfoClientThread(callback)); + sInstrumentation.waitForIdleSync(); + + Mockito.verify(callback).provideWindowSurfaceInfo( + vri.getWindowFlags(), Process.myUid(), vri.getSurfaceControl()); + } + private void launchActivity() { final Object waitObject = new Object(); final int[] location = new int[2]; diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java index e6361e10cfa7..6adceb96d977 100644 --- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java +++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java @@ -230,7 +230,9 @@ public class InsetsSourceConsumerTest { new InsetsSourceControl(ID_STATUS_BAR, statusBars(), mLeash, false /* initialVisible */, new Point(), Insets.NONE), new int[1], hideTypes, new int[1], new int[1]); - assertTrue(mRemoveSurfaceCalled); + if (!android.view.inputmethod.Flags.refactorInsetsController()) { + assertTrue(mRemoveSurfaceCalled); + } assertEquals(0, hideTypes[0]); }); diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index a289df0441e5..c40137f1bd34 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -16,8 +16,6 @@ package android.view; -import static android.app.UiModeManager.MODE_NIGHT_NO; -import static android.app.UiModeManager.MODE_NIGHT_YES; import static android.util.SequenceUtils.getInitSeq; import static android.view.HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING; import static android.view.InputDevice.SOURCE_ROTARY_ENCODER; @@ -69,10 +67,8 @@ import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; import android.app.Instrumentation; import android.app.UiModeManager; -import android.app.UiModeManager.ForceInvertType; import android.content.Context; import android.graphics.ForceDarkType; -import android.graphics.ForceDarkType.ForceDarkTypeDef; import android.graphics.Rect; import android.hardware.display.DisplayManagerGlobal; import android.os.Binder; @@ -97,12 +93,9 @@ import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.ShellIdentityUtils; -import com.android.compatibility.common.util.TestUtils; import com.android.cts.input.BlockingQueueEventVerifier; import com.android.window.flags.Flags; -import com.google.common.truth.Expect; - import org.hamcrest.Matcher; import org.junit.After; import org.junit.AfterClass; @@ -131,8 +124,6 @@ public class ViewRootImplTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - @Rule - public final Expect mExpect = Expect.create(); private ViewRootImpl mViewRootImpl; private View mView; @@ -1516,34 +1507,49 @@ public class ViewRootImplTest { } @Test - @RequiresFlagsEnabled(FLAG_FORCE_INVERT_COLOR) - public void updateConfiguration_returnsExpectedForceDarkMode() { - waitForSystemNightModeActivated(true); - - verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ true, - UiModeManager.FORCE_INVERT_TYPE_DARK, ForceDarkType.FORCE_INVERT_COLOR_DARK); - verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ false, - UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); - verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ true, - UiModeManager.FORCE_INVERT_TYPE_DARK, ForceDarkType.FORCE_INVERT_COLOR_DARK); - verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ false, - UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); - - waitForSystemNightModeActivated(false); - - verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ true, - UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); - verifyForceDarkType(/* isAppInNightMode= */ true, /* isForceInvertEnabled= */ false, - UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); - verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ true, - UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); - verifyForceDarkType(/* isAppInNightMode= */ false, /* isForceInvertEnabled= */ false, - UiModeManager.FORCE_INVERT_TYPE_OFF, ForceDarkType.NONE); + public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() { + mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + Settings.Secure.putInt( + sContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, + /* value= */ 0 + ); + var uiModeManager = sContext.getSystemService(UiModeManager.class); + uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); + }); + + sInstrumentation.runOnMainSync(() -> + mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()) + ); + + assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE); + } + + @Test + public void forceInvertOnDarkThemeOff_forceDarkModeEnabled() { + mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); + ShellIdentityUtils.invokeWithShellPermissions(() -> { + Settings.Secure.putInt( + sContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, + /* value= */ 1 + ); + var uiModeManager = sContext.getSystemService(UiModeManager.class); + uiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO); + }); + + sInstrumentation.runOnMainSync(() -> + mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()) + ); + + assertThat(mViewRootImpl.determineForceDarkType()) + .isEqualTo(ForceDarkType.FORCE_INVERT_COLOR_DARK); } @Test - @EnableFlags(FLAG_FORCE_INVERT_COLOR) public void forceInvertOffForceDarkOff_forceDarkModeDisabled() { + mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); ShellIdentityUtils.invokeWithShellPermissions(() -> { Settings.Secure.putInt( sContext.getContentResolver(), @@ -1556,14 +1562,15 @@ public class ViewRootImplTest { }); sInstrumentation.runOnMainSync(() -> - mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())); + mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()) + ); assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.NONE); } @Test - @EnableFlags(FLAG_FORCE_INVERT_COLOR) public void forceInvertOffForceDarkOn_forceDarkModeEnabled() { + mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); ShellIdentityUtils.invokeWithShellPermissions(() -> { Settings.Secure.putInt( sContext.getContentResolver(), @@ -1575,7 +1582,8 @@ public class ViewRootImplTest { }); sInstrumentation.runOnMainSync(() -> - mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())); + mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId()) + ); assertThat(mViewRootImpl.determineForceDarkType()).isEqualTo(ForceDarkType.FORCE_DARK); } @@ -1782,39 +1790,4 @@ public class ViewRootImplTest { () -> view.getViewTreeObserver().removeOnDrawListener(listener)); } } - - private void waitForSystemNightModeActivated(boolean active) { - ShellIdentityUtils.invokeWithShellPermissions(() -> - sInstrumentation.runOnMainSync(() -> { - var uiModeManager = sContext.getSystemService(UiModeManager.class); - uiModeManager.setNightModeActivated(active); - })); - sInstrumentation.waitForIdleSync(); - } - - private void verifyForceDarkType(boolean isAppInNightMode, boolean isForceInvertEnabled, - @ForceInvertType int expectedForceInvertType, - @ForceDarkTypeDef int expectedForceDarkType) { - var uiModeManager = sContext.getSystemService(UiModeManager.class); - ShellIdentityUtils.invokeWithShellPermissions(() -> { - uiModeManager.setApplicationNightMode( - isAppInNightMode ? MODE_NIGHT_YES : MODE_NIGHT_NO); - Settings.Secure.putInt( - sContext.getContentResolver(), - Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED, - isForceInvertEnabled ? 1 : 0); - }); - - sInstrumentation.runOnMainSync(() -> - mViewRootImpl.updateConfiguration(sContext.getDisplayNoVerify().getDisplayId())); - try { - TestUtils.waitUntil("Waiting for force invert state changed", - () -> (uiModeManager.getForceInvertState() == expectedForceInvertType)); - } catch (Exception e) { - Log.e(TAG, "Unexpected error trying to apply force invert state. " + e); - e.printStackTrace(); - } - - mExpect.that(mViewRootImpl.determineForceDarkType()).isEqualTo(expectedForceDarkType); - } } diff --git a/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java b/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java new file mode 100644 index 000000000000..c66e10079bc8 --- /dev/null +++ b/core/tests/coretests/src/android/view/ViewRootRectTrackerTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.testng.AssertJUnit.assertEquals; + +import android.graphics.Rect; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.google.common.collect.Lists; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Collections; +import java.util.List; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class ViewRootRectTrackerTest { + private ViewRootRectTracker mTracker; + private final List<Rect> mRects = Lists.newArrayList(new Rect(0, 0, 5, 5), + new Rect(5, 5, 10, 10)); + + @Before + public void setUp() { + mTracker = new ViewRootRectTracker(v -> Collections.emptyList()); + } + + @Test + public void setRootRectsAndComputeTest() { + mTracker.setRootRects(mRects); + mTracker.computeChanges(); + assertEquals(mRects, mTracker.getLastComputedRects()); + } + + @Test + public void waitingForComputeChangesTest() { + mTracker.setRootRects(mRects); + assertTrue(mTracker.isWaitingForComputeChanges()); + mTracker.computeChangedRects(); + assertFalse(mTracker.isWaitingForComputeChanges()); + + View mockView = mock(View.class); + mTracker.updateRectsForView(mockView); + assertTrue(mTracker.isWaitingForComputeChanges()); + mTracker.computeChangedRects(); + assertFalse(mTracker.isWaitingForComputeChanges()); + } +} diff --git a/data/keyboards/Vendor_0957_Product_0001.kl b/data/keyboards/Vendor_0957_Product_0001.kl index 87cb942602f7..0241f36e9ae6 100644 --- a/data/keyboards/Vendor_0957_Product_0001.kl +++ b/data/keyboards/Vendor_0957_Product_0001.kl @@ -72,6 +72,8 @@ key usage 0x000c009F NOTIFICATION key usage 0x000c008D GUIDE key usage 0x000c0089 TV +key usage 0x000c0187 FEATURED_APP_1 WAKE #FreeTv + key usage 0x000c009C CHANNEL_UP key usage 0x000c009D CHANNEL_DOWN diff --git a/graphics/java/android/framework_graphics.aconfig b/graphics/java/android/framework_graphics.aconfig index a63cbee4d707..fdbee3ccbebe 100644 --- a/graphics/java/android/framework_graphics.aconfig +++ b/graphics/java/android/framework_graphics.aconfig @@ -42,3 +42,11 @@ flag { description: "Add DISPLAY_BT2020 ColorSpace support" bug: "344038816" } + +flag { + name: "gradient_drawable_shape_rounded_cap" + is_fixed_read_only: true + namespace: "core_graphics" + description: "Make GradientDrawable support drawing ring with rounded stroke cap." + bug: "380000245" +} diff --git a/graphics/java/android/graphics/FrameInfo.java b/graphics/java/android/graphics/FrameInfo.java index 7d236d203201..3b8f46630344 100644 --- a/graphics/java/android/graphics/FrameInfo.java +++ b/graphics/java/android/graphics/FrameInfo.java @@ -93,10 +93,12 @@ public final class FrameInfo { // Interval between two consecutive frames public static final int FRAME_INTERVAL = 11; + // Workload target deadline for a frame + public static final int WORKLOAD_TARGET = 12; + // Must be the last one // This value must be in sync with `UI_THREAD_FRAME_INFO_SIZE` in FrameInfo.h - // In calculating size, + 1 for Flags, and + 1 for WorkloadTarget from FrameInfo.h - private static final int FRAME_INFO_SIZE = FRAME_INTERVAL + 2; + private static final int FRAME_INFO_SIZE = WORKLOAD_TARGET + 1; /** checkstyle */ public void setVsync(long intendedVsync, long usedVsync, long frameTimelineVsyncId, @@ -108,6 +110,7 @@ public final class FrameInfo { frameInfo[FRAME_DEADLINE] = frameDeadline; frameInfo[FRAME_START_TIME] = frameStartTime; frameInfo[FRAME_INTERVAL] = frameInterval; + frameInfo[WORKLOAD_TARGET] = frameDeadline - intendedVsync; } /** checkstyle */ diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index 65854dd51a91..ef6b72871415 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -658,6 +658,13 @@ public class HardwareRenderer { } /** + * @hide + */ + public void addObserver(long nativeObserver) { + nAddObserver(mNativeProxy, nativeObserver); + } + + /** * TODO: Public API this? * * @hide @@ -667,6 +674,13 @@ public class HardwareRenderer { } /** + * @hide + */ + public void removeObserver(long nativeObserver) { + nRemoveObserver(mNativeProxy, nativeObserver); + } + + /** * Sets the desired color mode on this renderer. Whether or not the actual rendering * will use the requested colorMode depends on the hardware support for such rendering. * diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java index 3543e991924e..db2376e008f5 100644 --- a/graphics/java/android/graphics/RuntimeShader.java +++ b/graphics/java/android/graphics/RuntimeShader.java @@ -20,6 +20,7 @@ import android.annotation.ColorInt; import android.annotation.ColorLong; import android.annotation.FlaggedApi; import android.annotation.NonNull; +import android.annotation.Nullable; import android.util.ArrayMap; import android.view.Window; @@ -76,6 +77,7 @@ import libcore.util.NativeAllocationRegistry; * Additionally, if the shader is invoked by another using {@link #setInputShader(String, Shader)}, * then that parent shader may modify the input coordinates arbitrarily.</p> * + * <a id="agsl-and-color-spaces"/> * <h3>AGSL and Color Spaces</h3> * <p>Android Graphics and by extension {@link RuntimeShader} are color managed. The working * {@link ColorSpace} for an AGSL shader is defined to be the color space of the destination, which @@ -267,6 +269,8 @@ public class RuntimeShader extends Shader { private ArrayMap<String, ColorFilter> mColorFilterUniforms = new ArrayMap<>(); private ArrayMap<String, RuntimeXfermode> mXfermodeUniforms = new ArrayMap<>(); + private ColorSpace mWorkingColorSpace = null; + /** * Creates a new RuntimeShader. @@ -286,6 +290,35 @@ public class RuntimeShader extends Shader { } /** + * Sets the working color space for this shader. That is, the shader will be evaluated + * in the given colorspace before being converted to the output destination's colorspace. + * + * <p>By default the RuntimeShader is evaluated in the context of the + * <a href="#agsl-and-color-spaces">destination colorspace</a>. By calling this method + * that can be overridden to force the shader to be evaluated in the given colorspace first + * before then being color converted to the destination colorspace.</p> + * + * @param colorSpace The ColorSpace to evaluate in. Must be an {@link ColorSpace#getModel() RGB} + * ColorSpace. Passing null restores default behavior of working in the + * destination colorspace. + * @throws IllegalArgumentException If the colorspace is not RGB + */ + @FlaggedApi(Flags.FLAG_SHADER_COLOR_SPACE) + public void setWorkingColorSpace(@Nullable ColorSpace colorSpace) { + if (colorSpace != null && colorSpace.getModel() != ColorSpace.Model.RGB) { + throw new IllegalArgumentException("ColorSpace must be RGB, given " + colorSpace); + } + if (mWorkingColorSpace != colorSpace) { + mWorkingColorSpace = colorSpace; + if (mWorkingColorSpace != null) { + // Just to enforce this can be resolved instead of erroring out later + mWorkingColorSpace.getNativeInstance(); + } + discardNativeInstance(); + } + } + + /** * Sets the uniform color value corresponding to this shader. If the shader does not have a * uniform with that name or if the uniform is declared with a type other than vec3 or vec4 and * corresponding layout(color) annotation then an IllegalArgumentException is thrown. @@ -578,7 +611,8 @@ public class RuntimeShader extends Shader { /** @hide */ @Override protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) { - return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix); + return nativeCreateShader(mNativeInstanceRuntimeShaderBuilder, nativeMatrix, + mWorkingColorSpace != null ? mWorkingColorSpace.getNativeInstance() : 0); } /** @hide */ @@ -589,6 +623,8 @@ public class RuntimeShader extends Shader { private static native long nativeGetFinalizer(); private static native long nativeCreateBuilder(String agsl); private static native long nativeCreateShader(long shaderBuilder, long matrix); + private static native long nativeCreateShader(long shaderBuilder, long matrix, + long colorSpacePtr); private static native void nativeUpdateUniforms( long shaderBuilder, String uniformName, float[] uniforms, boolean isColor); private static native void nativeUpdateUniforms( diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 29d033e64aea..ff1dc93d787b 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -16,7 +16,11 @@ package android.graphics.drawable; +import static com.android.graphics.flags.Flags.FLAG_GRADIENT_DRAWABLE_SHAPE_ROUNDED_CAP; +import static com.android.graphics.flags.Flags.gradientDrawableShapeRoundedCap; + import android.annotation.ColorInt; +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.NonNull; @@ -125,8 +129,14 @@ public class GradientDrawable extends Drawable { */ public static final int RING = 3; + /** + * Shape is an arc. + */ + @FlaggedApi(FLAG_GRADIENT_DRAWABLE_SHAPE_ROUNDED_CAP) + public static final int ARC = 4; + /** @hide */ - @IntDef({RECTANGLE, OVAL, LINE, RING}) + @IntDef({RECTANGLE, OVAL, LINE, RING, ARC}) @Retention(RetentionPolicy.SOURCE) public @interface Shape {} @@ -167,6 +177,17 @@ public class GradientDrawable extends Drawable { @Retention(RetentionPolicy.SOURCE) public @interface RadiusType {} + private static final int BUTT = 0; + + private static final int ROUND = 1; + + private static final int SQUARE = 2; + + /** @hide */ + @IntDef({BUTT, ROUND, SQUARE}) + @Retention(RetentionPolicy.SOURCE) + public @interface StrokeCap {} + private static final float DEFAULT_INNER_RADIUS_RATIO = 3.0f; private static final float DEFAULT_THICKNESS_RATIO = 9.0f; @@ -191,6 +212,8 @@ public class GradientDrawable extends Drawable { private boolean mMutated; private Path mRingPath; private boolean mPathIsDirty = true; + private Path mArcPath; + private Path mArcOutlinePath; /** Current gradient radius, valid when {@link #mGradientIsDirty} is false. */ private float mGradientRadius; @@ -850,6 +873,55 @@ public class GradientDrawable extends Drawable { } break; } + case ARC: + if (gradientDrawableShapeRoundedCap()) { + // TODO(b/394988176): Consider applying ARC drawing logic to RING shape. + float centerX = mRect.centerX(); + float centerY = mRect.centerY(); + float thickness = + st.mThickness != -1 ? st.mThickness + : mRect.width() / st.mThicknessRatio; + float radius = st.mInnerRadius != -1 ? st.mInnerRadius + : mRect.width() / st.mInnerRadiusRatio; + radius -= thickness; + float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f; + mRect.set(centerX - radius, centerY - radius, centerX + radius, + centerY + radius); + + // Prepare paint. Set style to STROKE for purpose of drawing line ARC. + mFillPaint.setStyle(Paint.Style.STROKE); + mFillPaint.setStrokeWidth(thickness); + mFillPaint.setStrokeCap(getStrokeLineCapForPaint(st.mStrokeCap)); + canvas.drawArc(mRect, 0.0f, sweep, /* useCenter= */ false, mFillPaint); + + if (haveStroke) { + if (mArcPath == null) { + mArcPath = new Path(); + } else { + mArcPath.reset(); + } + if (mArcOutlinePath == null) { + mArcOutlinePath = new Path(); + } else { + mArcOutlinePath.reset(); + } + if (sweep == 360f) { + mArcPath.addOval(mRect, Path.Direction.CW); + } else { + mArcPath.arcTo(mRect, 0.0f, sweep, /* forceMoveTo= */ false); + } + + // The arc path doesn't have width. So, to get the outline of the result arc + // shape, we need to apply the paint effect to the path; then use the + // output as the result outline. + mFillPaint.getFillPath(mArcPath, mArcOutlinePath); + canvas.drawPath(mArcOutlinePath, mStrokePaint); + } + + // Restore to FILL + mFillPaint.setStyle(Paint.Style.FILL); + break; + } case RING: Path path = buildRing(st); canvas.drawPath(path, mFillPaint); @@ -993,6 +1065,36 @@ public class GradientDrawable extends Drawable { } /** + * Return current drawable's stroke line cap. Note that this is only respected when drawable is + * {@link Shape#ARC}. + * + * @return the {@link StrokeCap} of current drawable. + * @attr ref android.R.styleable#GradientDrawable_strokeCap + * @see #setStrokeCap(int) + * + * @hide + */ + @StrokeCap + public int getStrokeCap() { + return mGradientState.mStrokeCap; + } + + /** + * Configure the stroke line cap type that drawable will use while drawing. Note that this is + * only respected when drawable is {@link Shape#ARC}. + * + * @param strokeCapType the stroke line cap type that the drawable will use while drawing. + * @attr ref android.R.styleable#GradientDrawable_strokeCap + * @see #getStrokeCap + * + * @hide + */ + public void setStrokeCap(@StrokeCap int strokeCapType) { + mGradientState.mStrokeCap = strokeCapType; + invalidateSelf(); + } + + /** * Configure the padding of the gradient shape * @param left Left padding of the gradient shape * @param top Top padding of the gradient shape @@ -1066,6 +1168,15 @@ public class GradientDrawable extends Drawable { return ringPath; } + private Paint.Cap getStrokeLineCapForPaint(@StrokeCap int strokeLineCap) { + return switch (strokeLineCap) { + case BUTT -> Paint.Cap.BUTT; + case ROUND -> Paint.Cap.ROUND; + case SQUARE -> Paint.Cap.SQUARE; + default -> Paint.Cap.SQUARE; + }; + } + /** * Changes this drawable to use a single color instead of a gradient. * <p> @@ -1484,7 +1595,7 @@ public class GradientDrawable extends Drawable { state.mShape = a.getInt(R.styleable.GradientDrawable_shape, state.mShape); state.mDither = a.getBoolean(R.styleable.GradientDrawable_dither, state.mDither); - if (state.mShape == RING) { + if (state.mShape == RING || state.mShape == ARC) { state.mInnerRadius = a.getDimensionPixelSize( R.styleable.GradientDrawable_innerRadius, state.mInnerRadius); @@ -1503,6 +1614,9 @@ public class GradientDrawable extends Drawable { state.mUseLevelForShape = a.getBoolean( R.styleable.GradientDrawable_useLevel, state.mUseLevelForShape); + + state.mStrokeCap = a.getInt( + R.styleable.GradientDrawable_strokeCap, state.mStrokeCap); } final int tintMode = a.getInt(R.styleable.GradientDrawable_tintMode, -1); @@ -2045,6 +2159,9 @@ public class GradientDrawable extends Drawable { public int mInnerRadius = -1; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124050218) public int mThickness = -1; + @UnsupportedAppUsage(trackingBug = 380000245) + @StrokeCap public int mStrokeCap = ROUND; + public boolean mDither = false; public Insets mOpticalInsets = Insets.NONE; diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png Binary files differnew file mode 100644 index 000000000000..15198748eea5 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png Binary files differnew file mode 100644 index 000000000000..99673f6400e9 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubbleBar.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png Binary files differnew file mode 100644 index 000000000000..ba4ebab75a7e --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_10_90.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png Binary files differnew file mode 100644 index 000000000000..b3ff64401a96 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_bubble_split_90_10.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png Binary files differnew file mode 100644 index 000000000000..534e320a0596 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png Binary files differnew file mode 100644 index 000000000000..67c9f49171ba --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_10_90.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png Binary files differnew file mode 100644 index 000000000000..a0fb4902a6f3 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_landscape_dragZones_expandedView_split_90_10.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png Binary files differnew file mode 100644 index 000000000000..27b35d447868 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png Binary files differnew file mode 100644 index 000000000000..11528a028a8f --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubbleBar.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png Binary files differnew file mode 100644 index 000000000000..ef9937700c08 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_10_90.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png Binary files differnew file mode 100644 index 000000000000..f0cf08bfcf4e --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_bubble_split_90_10.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png Binary files differnew file mode 100644 index 000000000000..bbaafb39845a --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/foldable_inner/light_portrait_dragZones_expandedView.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png Binary files differnew file mode 100644 index 000000000000..38ebf3f3201a --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubble.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png Binary files differnew file mode 100644 index 000000000000..2e4fd51e3932 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_bubbleBar.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png Binary files differnew file mode 100644 index 000000000000..a1ba9fb50d6a --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_landscape_dragZones_expandedView.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png Binary files differnew file mode 100644 index 000000000000..51bb15e10d30 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubble.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png Binary files differnew file mode 100644 index 000000000000..b643e2a69b2c --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_bubbleBar.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png Binary files differnew file mode 100644 index 000000000000..e6eeab7129be --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/tablet/light_portrait_dragZones_expandedView.png diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt b/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt new file mode 100644 index 000000000000..24f43d347163 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentScreenshotTests/src/com/android/wm/shell/shared/bubbles/DragZoneFactoryScreenshotTest.kt @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.shared.bubbles + +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable +import android.view.View +import android.view.WindowManager +import android.widget.FrameLayout +import androidx.annotation.ColorInt +import androidx.core.graphics.blue +import androidx.core.graphics.green +import androidx.core.graphics.red +import androidx.core.graphics.toColorInt +import androidx.test.core.app.ApplicationProvider.getApplicationContext +import com.android.wm.shell.shared.bubbles.DragZoneFactory.DesktopWindowModeChecker +import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker +import com.android.wm.shell.shared.bubbles.DragZoneFactory.SplitScreenModeChecker.SplitScreenMode +import com.android.wm.shell.testing.goldenpathmanager.WMShellGoldenPathManager +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters +import platform.test.screenshot.DeviceEmulationSpec +import platform.test.screenshot.Displays +import platform.test.screenshot.ViewScreenshotTestRule +import platform.test.screenshot.ViewScreenshotTestRule.Mode +import platform.test.screenshot.getEmulatedDevicePathConfig + +@RunWith(ParameterizedAndroidJunit4::class) +class DragZoneFactoryScreenshotTest(private val param: Param) { + companion object { + @Parameters(name = "{0}") + @JvmStatic + fun getTestSpecs(): List<Param> { + val params = mutableListOf<Param>() + val draggedObjects = + listOf( + DraggedObject.Bubble(BubbleBarLocation.LEFT), + DraggedObject.BubbleBar(BubbleBarLocation.LEFT), + DraggedObject.ExpandedView(BubbleBarLocation.LEFT), + ) + DeviceEmulationSpec.forDisplays(Displays.Tablet, isDarkTheme = false).forEach { tablet + -> + draggedObjects.forEach { draggedObject -> + params.add(Param(tablet, draggedObject, SplitScreenMode.NONE)) + } + } + DeviceEmulationSpec.forDisplays(Displays.FoldableInner, isDarkTheme = false).forEach { + foldable -> + draggedObjects.forEach { draggedObject -> + params.add(Param(foldable, draggedObject, SplitScreenMode.NONE)) + val isBubble = draggedObject is DraggedObject.Bubble + val isExpandedView = draggedObject is DraggedObject.ExpandedView + val addMoreSplitModes = isBubble || (isExpandedView && foldable.isLandscape) + if (addMoreSplitModes) { + params.add(Param(foldable, draggedObject, SplitScreenMode.SPLIT_10_90)) + params.add(Param(foldable, draggedObject, SplitScreenMode.SPLIT_90_10)) + } + } + } + return params + } + } + + class Param( + val emulationSpec: DeviceEmulationSpec, + val draggedObject: DraggedObject, + val splitScreenMode: SplitScreenMode + ) { + private val draggedObjectName = + when (draggedObject) { + is DraggedObject.Bubble -> "bubble" + is DraggedObject.BubbleBar -> "bubbleBar" + is DraggedObject.ExpandedView -> "expandedView" + } + + private val splitScreenModeName = + when (splitScreenMode) { + SplitScreenMode.NONE -> "" + SplitScreenMode.SPLIT_50_50 -> "_split_50_50" + SplitScreenMode.SPLIT_10_90 -> "_split_10_90" + SplitScreenMode.SPLIT_90_10 -> "_split_90_10" + } + + val testName = "$draggedObjectName$splitScreenModeName" + + override fun toString() = "${emulationSpec}_$testName" + } + + @get:Rule + val screenshotRule = + ViewScreenshotTestRule( + param.emulationSpec, + WMShellGoldenPathManager(getEmulatedDevicePathConfig(param.emulationSpec)) + ) + + private val context = getApplicationContext<Context>() + + @Test + fun dragZones() { + screenshotRule.screenshotTest("dragZones_${param.testName}", mode = Mode.MatchSize) { + activity -> + activity.actionBar?.hide() + val dragZoneFactory = createDragZoneFactory() + val dragZones = dragZoneFactory.createSortedDragZones(param.draggedObject) + val container = FrameLayout(context) + dragZones.forEach { zone -> container.addZoneView(zone) } + container + } + } + + private fun createDragZoneFactory(): DragZoneFactory { + val deviceConfig = + DeviceConfig.create(context, context.getSystemService(WindowManager::class.java)!!) + val splitScreenModeChecker = SplitScreenModeChecker { param.splitScreenMode } + val desktopWindowModeChecker = DesktopWindowModeChecker { true } + return DragZoneFactory( + context, + deviceConfig, + splitScreenModeChecker, + desktopWindowModeChecker + ) + } + + private fun FrameLayout.addZoneView(zone: DragZone) { + val view = View(context) + this.addView(view, 0) + view.layoutParams = FrameLayout.LayoutParams(zone.bounds.width(), zone.bounds.height()) + view.background = createZoneDrawable(zone.color) + view.x = zone.bounds.left.toFloat() + view.y = zone.bounds.top.toFloat() + } + + private fun createZoneDrawable(@ColorInt color: Int): Drawable { + val shape = GradientDrawable() + shape.shape = GradientDrawable.RECTANGLE + shape.setColor(Color.argb(128, color.red, color.green, color.blue)) + shape.setStroke(2, color) + return shape + } + + private val DragZone.color: Int + @ColorInt + get() = + when (this) { + is DragZone.Bubble -> "#3F5C8B".toColorInt() + is DragZone.Dismiss -> "#8B3F3F".toColorInt() + is DragZone.Split -> "#89B675".toColorInt() + is DragZone.FullScreen -> "#4ED075".toColorInt() + is DragZone.DesktopWindow -> "#EC928E".toColorInt() + } +} diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml index 5444c26e9ec9..b4d594f0c06b 100644 --- a/libs/WindowManager/Shell/res/values-af/strings.xml +++ b/libs/WindowManager/Shell/res/values-af/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Apphandvatsel"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Volskerm"</string> - <string name="desktop_text" msgid="1077633567027630454">"Rekenaarmodus"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Verdeelde skerm"</string> <string name="more_button_text" msgid="3655388105592893530">"Meer"</string> <string name="float_button_text" msgid="9221657008391364581">"Sweef"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Verander aspekverhouding"</string> <string name="close_text" msgid="4986518933445178928">"Maak toe"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Maak kieslys toe"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Maak kieslys oop"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimeer skerm"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Verander grootte"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App kan nie hierheen geskuif word nie"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Verander grootte van linkerkantse venster"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Verander grootte van regterkantse venster"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimeer of stel venstergrootte terug"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Gaan na deelskermmodus"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Gaan na werkskermvenstermodus"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Verander grootte van linkerkantse venster"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Verander grootte van regterkantse venster"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimeer of stel venstergrootte terug"</string> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index f3bc29d95673..9ec8001e1b9c 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"የመተግበሪያ መያዣ"</string> <string name="app_icon_text" msgid="2823268023931811747">"የመተግበሪያ አዶ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ሙሉ ማያ"</string> - <string name="desktop_text" msgid="1077633567027630454">"የዴስክቶፕ ሁነታ"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"የተከፈለ ማያ ገፅ"</string> <string name="more_button_text" msgid="3655388105592893530">"ተጨማሪ"</string> <string name="float_button_text" msgid="9221657008391364581">"ተንሳፋፊ"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ምጥጥነ ገፅታ ለውጥ"</string> <string name="close_text" msgid="4986518933445178928">"ዝጋ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ምናሌ ዝጋ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ምናሌን ክፈት"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"የማያ ገጹ መጠን አሳድግ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"መጠን ቀይር"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"መተግበሪያ ወደዚህ መንቀሳቀስ አይችልም"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"የመተግበሪያ መስኮትን ወደ ግራ መጠን ቀይር"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"የመተግበሪያ መስኮትን ወደ ቀኝ መጠን ቀይር"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ወደ የተከፈለ ማያ ገፅ ሁነታ ግባ"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ወደ የዴስክቶፕ መስኮት ሁነታ ግባ"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"መስኮትን ወደ ግራ መጠን ቀይር"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"መስኮትን ወደ ቀኝ መጠን ቀይር"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 60f27cfdee91..16809221ca77 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"مقبض التطبيق"</string> <string name="app_icon_text" msgid="2823268023931811747">"رمز التطبيق"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ملء الشاشة"</string> - <string name="desktop_text" msgid="1077633567027630454">"وضع سطح المكتب"</string> + <string name="desktop_text" msgid="1582173066857454541">"العرض المخصّص للكمبيوتر المكتبي"</string> <string name="split_screen_text" msgid="1396336058129570886">"تقسيم الشاشة"</string> <string name="more_button_text" msgid="3655388105592893530">"المزيد"</string> <string name="float_button_text" msgid="9221657008391364581">"نافذة عائمة"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغيير نسبة العرض إلى الارتفاع"</string> <string name="close_text" msgid="4986518933445178928">"إغلاق"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"إغلاق القائمة"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"فتح القائمة"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (العرض المخصّص للكمبيوتر المكتبي)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"تكبير الشاشة إلى أقصى حدّ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغيير الحجم"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"لا يمكن نقل التطبيق إلى هنا"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"تغيير حجم نافذة التطبيق بمحاذاتها إلى اليمين"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"تغيير حجم نافذة التطبيق بمحاذاتها إلى اليسار"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"تكبير حجم النافذة أو استعادته"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"تفعيل \"وضع تقسيم الشاشة\""</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"تفعيل وضع عرض المحتوى في النافذة الحالية على سطح المكتب"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"فتح القائمة"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"تفعيل \"<xliff:g id="WINDOWING_MODE">%1$s</xliff:g>\""</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"تغيير حجم النافذة بمحاذاتها إلى اليمين"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"تغيير حجم النافذة بمحاذاتها إلى اليسار"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"تكبير حجم النافذة أو استعادته"</string> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index 0f433479e130..05860c25db89 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"এপৰ হেণ্ডেল"</string> <string name="app_icon_text" msgid="2823268023931811747">"এপৰ চিহ্ন"</string> <string name="fullscreen_text" msgid="1162316685217676079">"সম্পূৰ্ণ স্ক্ৰীন"</string> - <string name="desktop_text" msgid="1077633567027630454">"ডেস্কটপ ম’ড"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"বিভাজিত স্ক্ৰীন"</string> <string name="more_button_text" msgid="3655388105592893530">"অধিক"</string> <string name="float_button_text" msgid="9221657008391364581">"ওপঙা"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"আকাৰৰ অনুপাত সলনি কৰক"</string> <string name="close_text" msgid="4986518933445178928">"বন্ধ কৰক"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"মেনু বন্ধ কৰক"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"মেনু খোলক"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্ৰীন মেক্সিমাইজ কৰক"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"আকাৰ সলনি কৰক"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ইয়ালৈ এপ্টো আনিব নোৱাৰি"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"বাওঁফালে এপ্ ৱিণ্ড’ৰ আকাৰ সলনি কৰক"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"সোঁফালে এপ্ ৱিণ্ড’ৰ আকাৰ সলনি কৰক"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ৱিণ্ড’ৰ আকাৰ মেক্সিমাইজ বা পুনঃস্থাপন কৰক"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"বিভাজিত-স্ক্ৰীন ম’ড দিয়ক"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ডেস্কটপ ৱিণ্ড’ইং ম’ড দিয়ক"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"সোঁফাললৈ ৱিণ্ড’ৰ আকাৰ সলনি কৰক"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"বাওঁফাললৈ ৱিণ্ড’ৰ আকাৰ সলনি কৰক"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ৱিণ্ড’ৰ আকাৰ মেক্সিমাইজ বা পুনঃস্থাপন কৰক"</string> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index aced354ac826..ea64749c023e 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Tətbiq ləqəbi"</string> <string name="app_icon_text" msgid="2823268023931811747">"Tətbiq ikonası"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tam Ekran"</string> - <string name="desktop_text" msgid="1077633567027630454">"Masaüstü Rejimi"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Bölünmüş Ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Ardı"</string> <string name="float_button_text" msgid="9221657008391364581">"Üzən pəncərə"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tərəflər nisbətini dəyişin"</string> <string name="close_text" msgid="4986518933445178928">"Bağlayın"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menyunu bağlayın"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menyunu açın"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı maksimum böyüdün"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ölçüsünü dəyişin"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Tətbiqi bura köçürmək mümkün deyil"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Tətbiq pəncərəsinin ölçüsünü sola dəyişin"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Tətbiq pəncərəsinin ölçüsünü sağa dəyişin"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Bölünmüş ekran rejiminə daxil olun"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masaüstü pəncərə rejiminə daxil olun"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pəncərə ölçüsünü sola dəyişin"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pəncərə ölçüsünü sağa dəyişin"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string> diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml index b07c61258f4e..deec04f63270 100644 --- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml +++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Preko celog ekrana"</string> - <string name="desktop_text" msgid="1077633567027630454">"Režim za računare"</string> + <string name="desktop_text" msgid="1582173066857454541">"Prikaz za računare"</string> <string name="split_screen_text" msgid="1396336058129570886">"Podeljeni ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Još"</string> <string name="float_button_text" msgid="9221657008391364581">"Plutajuće"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promeni razmeru"</string> <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite meni"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvorite meni"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz za računare)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Povećaj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promeni veličinu"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija ne može da se premesti ovde"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Promenite veličinu prozora aplikacije nalevo"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Promenite veličinu prozora aplikacije nadesno"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Uvećajte ili vratite veličinu prozora"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Uđite u režim podeljenog ekrana"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Uđite u režim prozora na računaru"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Otvorite Meni"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Unesite <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promenite veličinu prozora nalevo"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promenite veličinu prozora nadesno"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Uvećajte ili vratite veličinu prozora"</string> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index 4c2950b5afa1..d26c37ba5e15 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Маркер праграмы"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок праграмы"</string> <string name="fullscreen_text" msgid="1162316685217676079">"На ўвесь экран"</string> - <string name="desktop_text" msgid="1077633567027630454">"Рэжым працоўнага стала"</string> + <string name="desktop_text" msgid="1582173066857454541">"Версія для камп’ютараў"</string> <string name="split_screen_text" msgid="1396336058129570886">"Падзяліць экран"</string> <string name="more_button_text" msgid="3655388105592893530">"Яшчэ"</string> <string name="float_button_text" msgid="9221657008391364581">"Зрабіць рухомым акном"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змяніць суадносіны бакоў"</string> <string name="close_text" msgid="4986518933445178928">"Закрыць"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыць меню"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Адкрыць меню"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (версія для камп’ютараў)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Разгарнуць на ўвесь экран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Змяніць памер"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Нельга перамясціць сюды праграму"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Змяніць памер акна (злева)"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Змяніць памер акна (справа)"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Разгарнуць акно ці аднавіць яго памер"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Уключыць рэжым падзеленага экрана"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Уключыць рэжым вокнаў працоўнага стала"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Адкрыць меню"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Увесці \"<xliff:g id="WINDOWING_MODE">%1$s</xliff:g>\""</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Змяніць памер акна і перамясціць да левага краю"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Змяніць памер акна і перамясціць да правага краю"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Разгарнуць акно ці аднавіць яго памер"</string> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index fcc4d83baf75..0bb59605b247 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Манипулатор за приложението"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона на приложението"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Цял екран"</string> - <string name="desktop_text" msgid="1077633567027630454">"Режим за настолни компютри"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Разделяне на екрана"</string> <string name="more_button_text" msgid="3655388105592893530">"Още"</string> <string name="float_button_text" msgid="9221657008391364581">"Плаващо"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промяна на съотношението"</string> <string name="close_text" msgid="4986518933445178928">"Затваряне"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затваряне на менюто"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отваряне на менюто"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Увеличаване на екрана"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Преоразмеряване"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложението не може да бъде преместено тук"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Преоразмеряване на прозореца на приложението наляво"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Преоразмеряване на прозореца на приложението надясно"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Увеличаване или възстановяване на размера на прозореца"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Активиране на режима за разделен екран"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Активиране на режима за настолни компютри"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Преоразмеряване на прозореца наляво"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Преоразмеряване на прозореца надясно"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Увеличаване или възстановяване на размера на прозореца"</string> diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml index b2c435e5ef0e..ae63e0402592 100644 --- a/libs/WindowManager/Shell/res/values-bn/strings.xml +++ b/libs/WindowManager/Shell/res/values-bn/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"অ্যাপের হ্যান্ডেল"</string> <string name="app_icon_text" msgid="2823268023931811747">"অ্যাপ আইকন"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ফুলস্ক্রিন"</string> - <string name="desktop_text" msgid="1077633567027630454">"ডেস্কটপ মোড"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"স্প্লিট স্ক্রিন"</string> <string name="more_button_text" msgid="3655388105592893530">"আরও"</string> <string name="float_button_text" msgid="9221657008391364581">"ফ্লোট"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"অ্যাস্পেক্ট রেশিও পরিবর্তন করুন"</string> <string name="close_text" msgid="4986518933445178928">"বন্ধ করুন"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"\'মেনু\' বন্ধ করুন"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"মেনু খুলুন"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"স্ক্রিন বড় করুন"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ছোট বড় করুন"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"অ্যাপটি এখানে সরানো যাবে না"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"বাঁদিকে অ্যাপ উইন্ডো রিসাইজ করুন"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ডানদিকে অ্যাপ উইন্ডো রিসাইজ করুন"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"স্প্লিট স্ক্রিন মোডে প্রবেশ করুন"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ডেস্কটপ উইন্ডোইং মোডে প্রবেশ করুন"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"বাঁদিকে উইন্ডো রিসাইজ করুন"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ডানদিকে উইন্ডো রিসাইজ করুন"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index 8c1619ce925c..b7c76b5f9762 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Ručica aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Cijeli ekran"</string> - <string name="desktop_text" msgid="1077633567027630454">"Način rada radne površine"</string> + <string name="desktop_text" msgid="1582173066857454541">"Prikaz na računalu"</string> <string name="split_screen_text" msgid="1396336058129570886">"Podijeljeni ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Više"</string> <string name="float_button_text" msgid="9221657008391364581">"Lebdeći"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promjena formata slike"</string> <string name="close_text" msgid="4986518933445178928">"Zatvaranje"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvaranje menija"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvaranje menija"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz na računalu)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiziraj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promijeni veličinu"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ne možete premjestiti aplikaciju ovdje"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Promjena veličine prozora aplikacije lijevo"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Promjena veličine prozora aplikacije desno"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimiziranje ili vraćanje veličine prozora"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Pokretanje načina rada podijeljenog ekrana"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Pokretanje načina rada s prozorima na radnoj površini"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Otvorite izbornik"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Unesite <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promjena veličine prozora i poravnanje lijevo"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promjena veličine prozora i poravnanje desno"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziranje ili vraćanje veličine prozora"</string> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index 37802f4c7f94..80dd3801c264 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Identificador de l\'aplicació"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona de l\'aplicació"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> - <string name="desktop_text" msgid="1077633567027630454">"Mode d\'escriptori"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Més"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotant"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Canvia la relació d\'aspecte"</string> <string name="close_text" msgid="4986518933445178928">"Tanca"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tanca el menú"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Obre el menú"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximitza la pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Canvia la mida"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"L\'aplicació no es pot moure aquí"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Canvia la mida de la finestra de l\'aplicació a l\'esquerra"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Canvia la mida de la finestra de l\'aplicació a la dreta"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximitza o restaura la mida de la finestra"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entra al mode de pantalla dividida"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entra al mode d\'enfinestrament a l\'escriptori"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Canvia la mida de la finestra a l\'esquerra"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Canvia la mida de la finestra a la dreta"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximitza o restaura la mida de la finestra"</string> diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml index c4514eb4ce8d..e47d1f60137e 100644 --- a/libs/WindowManager/Shell/res/values-cs/strings.xml +++ b/libs/WindowManager/Shell/res/values-cs/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Popisovač aplikace"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikace"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string> - <string name="desktop_text" msgid="1077633567027630454">"Režim počítače"</string> + <string name="desktop_text" msgid="1582173066857454541">"Zobrazení na počítači"</string> <string name="split_screen_text" msgid="1396336058129570886">"Rozdělená obrazovka"</string> <string name="more_button_text" msgid="3655388105592893530">"Více"</string> <string name="float_button_text" msgid="9221657008391364581">"Plovoucí"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Změnit poměr stran"</string> <string name="close_text" msgid="4986518933445178928">"Zavřít"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zavřít nabídku"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otevřít nabídku"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (zobrazení na počítači)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovat obrazovku"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Změnit velikost"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikaci sem nelze přesunout"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Změnit velikost okna aplikace vlevo"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Změnit velikost okna aplikace vpravo"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximalizovat nebo obnovit velikost okna"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Přechod do režimu rozdělené obrazovky"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Přejít do režimu okenního systému pro počítače"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Otevřít nabídku"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Přejít do režimu <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Přichytit okno vlevo"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Přichytit okno vpravo"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximalizovat nebo obnovit velikost okna"</string> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index e662a16ced1e..c465ce3d89fd 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Apphåndtag"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fuld skærm"</string> - <string name="desktop_text" msgid="1077633567027630454">"Computertilstand"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Opdelt skærm"</string> <string name="more_button_text" msgid="3655388105592893530">"Mere"</string> <string name="float_button_text" msgid="9221657008391364581">"Svævende"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Skift billedformat"</string> <string name="close_text" msgid="4986518933445178928">"Luk"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Luk menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Åbn menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimér skærm"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Tilpas størrelse"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apps kan ikke flyttes hertil"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Juster størrelsen på appvinduet til venstre"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Juster størrelsen på appvinduet til højre"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimer eller gendan vinduesstørrelse"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Åbn opdelt skærm"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Åbn tilstanden for vinduer på computeren"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Juster størrelsen på vinduet til venstre"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Juster størrelsen på vinduet til højre"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimer eller gendan vinduesstørrelse"</string> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index 7b21719bc880..567dd7a0c2a5 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"App-Ziehpunkt"</string> <string name="app_icon_text" msgid="2823268023931811747">"App-Symbol"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Vollbild"</string> - <string name="desktop_text" msgid="1077633567027630454">"Desktopmodus"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Splitscreen"</string> <string name="more_button_text" msgid="3655388105592893530">"Mehr"</string> <string name="float_button_text" msgid="9221657008391364581">"Frei schwebend"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Seitenverhältnis ändern"</string> <string name="close_text" msgid="4986518933445178928">"Schließen"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menü schließen"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menü öffnen"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Bildschirm maximieren"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Größe ändern"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Die App kann nicht hierher verschoben werden"</string> @@ -142,13 +144,15 @@ <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Wiederherstellen"</string> <string name="desktop_mode_maximize_menu_snap_left_button_text" msgid="8077452201179893424">"Links andocken"</string> <string name="desktop_mode_maximize_menu_snap_right_button_text" msgid="7117751068945657304">"Rechts andocken"</string> - <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Größe des linken App-Fensters anpassen"</string> - <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Größe des rechten App-Fensters anpassen"</string> + <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Größe des App-Fensters links anpassen"</string> + <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Größe des App-Fensters rechts anpassen"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Fenstergröße maximieren oder wiederherstellen"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Splitscreen-Modus aktivieren"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Desktop-Fenstermodus aktivieren"</string> - <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Fenstergröße links anpassen"</string> - <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Fenstergröße rechts anpassen"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> + <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Fenstergröße nach links anpassen"</string> + <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Fenstergröße nach rechts anpassen"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Fenstergröße maximieren oder wiederherstellen"</string> <string name="maximize_button_talkback_action_maximize_restore_text" msgid="4122441323153198455">"Fenstergröße maximieren oder wiederherstellen"</string> <string name="minimize_button_talkback_action_maximize_restore_text" msgid="8890767445425625935">"App-Fenster minimieren"</string> diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml index eb45a31c5d8a..489a4ce6b550 100644 --- a/libs/WindowManager/Shell/res/values-el/strings.xml +++ b/libs/WindowManager/Shell/res/values-el/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Λαβή εφαρμογής"</string> <string name="app_icon_text" msgid="2823268023931811747">"Εικονίδιο εφαρμογής"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Πλήρης οθόνη"</string> - <string name="desktop_text" msgid="1077633567027630454">"Λειτουργία επιφάνειας εργασίας"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Διαχωρισμός οθόνης"</string> <string name="more_button_text" msgid="3655388105592893530">"Περισσότερα"</string> <string name="float_button_text" msgid="9221657008391364581">"Κινούμενο"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Αλλαγή λόγου διαστάσεων"</string> <string name="close_text" msgid="4986518933445178928">"Κλείσιμο"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Κλείσιμο μενού"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Άνοιγμα μενού"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Μεγιστοποίηση οθόνης"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Αλλαγή μεγέθους"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Δεν είναι δυνατή η μετακίνηση της εφαρμογής εδώ"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Αλλαγή μεγέθους παραθύρου εφαρμογής αριστερά"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Αλλαγή μεγέθους παραθύρου εφαρμογής δεξιά"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Είσοδος στη λειτουργία διαχωρισμού οθόνης"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Είσοδος στη λειτουργία προσαρμογής σε παράθυρο υπολογιστή"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Αλλαγή μεγέθους παραθύρου προς τα αριστερά"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Αλλαγή μεγέθους παραθύρου προς τα δεξιά"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml index 8dc27dabfc2c..1a3d422eb736 100644 --- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> - <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> <string name="more_button_text" msgid="3655388105592893530">"More"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml index 20d141e7808c..e552f95c20c6 100644 --- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App Icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string> - <string name="desktop_text" msgid="1077633567027630454">"Desktop Mode"</string> + <string name="desktop_text" msgid="1582173066857454541">"Desktop View"</string> <string name="split_screen_text" msgid="1396336058129570886">"Split Screen"</string> <string name="more_button_text" msgid="3655388105592893530">"More"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close Menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open Menu"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Desktop View)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximize Screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximize or restore window size"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split screen mode"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Open Menu"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Enter <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximize or restore window size"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml index 8dc27dabfc2c..1a3d422eb736 100644 --- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> - <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> <string name="more_button_text" msgid="3655388105592893530">"More"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string> diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml index 8dc27dabfc2c..1a3d422eb736 100644 --- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml +++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"App handle"</string> <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Full screen"</string> - <string name="desktop_text" msgid="1077633567027630454">"Desktop mode"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split screen"</string> <string name="more_button_text" msgid="3655388105592893530">"More"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Change aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Close"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Close menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Open menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximise screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"App can\'t be moved here"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Resize app window left"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Resize app window right"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximise or restore window size"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Enter split-screen mode"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Enter desktop windowing mode"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index 24c2bed5e79e..93aa1b63fa26 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Controlador de la app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícono de la app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modo de escritorio"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Más"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotante"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string> <string name="close_text" msgid="4986518933445178928">"Cerrar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir el menú"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Cambiar el tamaño"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"No se puede mover la app aquí"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ajustar el tamaño de la ventana de la app hacia la izquierda"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ajustar el tamaño de la ventana de la app hacia la derecha"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizar o restablecer el tamaño de la ventana"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Activar el modo de pantalla dividida"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Ingresar al modo ventana de computadora"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ajustar el tamaño de la ventana hacia la izquierda"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ajustar el tamaño de la ventana hacia la derecha"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar o restablecer el tamaño de la ventana"</string> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index dd9635dccfcb..27c5b801dbba 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Controlador de la aplicación"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icono de la aplicación"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modo Escritorio"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Más"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotante"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar relación de aspecto"</string> <string name="close_text" msgid="4986518933445178928">"Cerrar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir menú"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Cambiar tamaño"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"La aplicación no se puede mover aquí"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Cambiar tamaño de la ventana de la aplicación izquierda"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Cambiar tamaño de la ventana de la aplicación derecha"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizar o restaurar tamaño de la ventana"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Activar modo Pantalla dividida"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Activar modo Escritorio basado en ventanas"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Cambiar tamaño de la ventana a la izquierda"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Cambiar tamaño de la ventana a la derecha"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar o restaurar tamaño de la ventana"</string> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index 56b5f0bb0874..c8ab83ef8eae 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Rakenduse element"</string> <string name="app_icon_text" msgid="2823268023931811747">"Rakenduse ikoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Täisekraan"</string> - <string name="desktop_text" msgid="1077633567027630454">"Lauaarvuti režiim"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Jagatud ekraanikuva"</string> <string name="more_button_text" msgid="3655388105592893530">"Rohkem"</string> <string name="float_button_text" msgid="9221657008391364581">"Hõljuv"</string> @@ -132,11 +133,12 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Kuvasuhte muutmine"</string> <string name="close_text" msgid="4986518933445178928">"Sule"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Sule menüü"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ava menüü"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Kuva täisekraanil"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Suuruse muutmine"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Rakendust ei saa siia teisaldada"</string> - <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Kaasahaarav"</string> + <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Mahuta"</string> <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Taasta"</string> <string name="desktop_mode_maximize_menu_maximize_button_text" msgid="3090199175564175845">"Maksimeeri"</string> <string name="desktop_mode_maximize_menu_restore_button_text" msgid="4234449220944704387">"Taasta"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Rakenduse akna suuruse muutmine vasakul"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Rakenduse akna suuruse muutmine paremal"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Akna suuruse maksimeerimine või taastamine"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Poolitatud ekraani režiimi sisenemine"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Töölaua akende kuvamise režiimi sisenemine"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Akna suuruse muutmine, vasakule"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Akna suuruse muutmine, paremale"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Akna suuruse maksimeerimine või taastamine"</string> diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml index 9898af0c394d..abd92ab758d0 100644 --- a/libs/WindowManager/Shell/res/values-eu/strings.xml +++ b/libs/WindowManager/Shell/res/values-eu/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Aplikazioaren kontrol-puntua"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aplikazioaren ikonoa"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantaila osoa"</string> - <string name="desktop_text" msgid="1077633567027630454">"Ordenagailuetarako modua"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantaila zatitzea"</string> <string name="more_button_text" msgid="3655388105592893530">"Gehiago"</string> <string name="float_button_text" msgid="9221657008391364581">"Leiho gainerakorra"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Aldatu aspektu-erlazioa"</string> <string name="close_text" msgid="4986518933445178928">"Itxi"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Itxi menua"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ireki menua"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Handitu pantaila"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Aldatu tamaina"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikazioa ezin da hona ekarri"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Aldatu aplikazioaren leihoaren tamaina eta eraman ezkerrera"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Aldatu aplikazioaren leihoaren tamaina eta eraman eskuinera"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizatu edo leheneratu leihoaren tamaina"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Sartu pantaila zatituaren moduan"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Sartu ordenagailuan leihoak erabiltzeko moduan"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Aldatu leihoaren tamaina eta eraman ezkerrera"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Aldatu leihoaren tamaina eta eraman eskuinera"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizatu edo leheneratu leihoaren tamaina"</string> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index 22ef61f62e13..651635a8cc1c 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"دستگیره برنامه"</string> <string name="app_icon_text" msgid="2823268023931811747">"نماد برنامه"</string> <string name="fullscreen_text" msgid="1162316685217676079">"تمامصفحه"</string> - <string name="desktop_text" msgid="1077633567027630454">"حالت رایانه"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"صفحهٔ دونیمه"</string> <string name="more_button_text" msgid="3655388105592893530">"بیشتر"</string> <string name="float_button_text" msgid="9221657008391364581">"شناور"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"تغییر نسبت ابعادی"</string> <string name="close_text" msgid="4986518933445178928">"بستن"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"بستن منو"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"باز کردن منو"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"بزرگ کردن صفحه"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"تغییر اندازه"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"برنامه را نمیتوان به اینجا منتقل کرد"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"تغییر اندازه پنجره برنامه در چپ"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"تغییر اندازه پنجره برنامه در راست"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"بیشینهسازی یا بازیابی اندازه پنجره"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ورود به حالت صفحه تقسیمشده"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"رفتن به حالت پردازش پنجرهای میز کار"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"تغییر اندازه پنجره به چپ"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"تغییر اندازه پنجره به راست"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"بیشینهسازی یا بازیابی اندازه پنجره"</string> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index b23c833fa453..47e9ea335db8 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Sovelluksen tunnus"</string> <string name="app_icon_text" msgid="2823268023931811747">"Sovelluskuvake"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Koko näyttö"</string> - <string name="desktop_text" msgid="1077633567027630454">"Työpöytätila"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Jaettu näyttö"</string> <string name="more_button_text" msgid="3655388105592893530">"Lisää"</string> <string name="float_button_text" msgid="9221657008391364581">"Kelluva ikkuna"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Vaihda kuvasuhdetta"</string> <string name="close_text" msgid="4986518933445178928">"Sulje"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Sulje valikko"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Avaa valikko"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Suurenna näyttö"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Muuta kokoa"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Sovellusta ei voi siirtää tänne"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Muuta vasemmanpuoleisen sovellusikkunan kokoa"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Muuta oikeanpuoleisen sovellusikkunan kokoa"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Suurenna ikkuna tai palauta ikkunan koko"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Avaa kahtia jaettu näyttö"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Siirry työpöydän ikkunointitilaan"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Muuta vasemmanpuoleisen ikkunan kokoa"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Muuta vasemmanpuoleisen ikkunan kokoa"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Suurenna ikkuna tai palauta ikkunan koko"</string> diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index 34b5b0acf753..dc2025ffeb68 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icône de l\'appli"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string> - <string name="desktop_text" msgid="1077633567027630454">"Mode Bureau"</string> + <string name="desktop_text" msgid="1582173066857454541">"Affichage sur un ordinateur de bureau"</string> <string name="split_screen_text" msgid="1396336058129570886">"Écran divisé"</string> <string name="more_button_text" msgid="3655388105592893530">"Plus"</string> <string name="float_button_text" msgid="9221657008391364581">"Flottant"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier les proportions"</string> <string name="close_text" msgid="4986518933445178928">"Fermer"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ouvrir le menu"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (affichage sur un ordinateur de bureau)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Agrandir l\'écran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionner"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionner la fenêtre de l\'appli à gauche"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionner la fenêtre de l\'appli à droite"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Agrandir ou restaurer la taille de la fenêtre"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entrer en mode Écran divisé"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entrer en mode Fenêtrage bureau"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Ouvrir le menu"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Entrez <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index be41bba34772..038a90dcb736 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icône d\'application"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Plein écran"</string> - <string name="desktop_text" msgid="1077633567027630454">"Mode ordinateur"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Écran partagé"</string> <string name="more_button_text" msgid="3655388105592893530">"Plus"</string> <string name="float_button_text" msgid="9221657008391364581">"Flottante"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Modifier le format"</string> <string name="close_text" msgid="4986518933445178928">"Fermer"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fermer le menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Ouvrir le menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mettre en plein écran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionner"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossible de déplacer l\'appli ici"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionner la fenêtre de l\'appli vers la gauche"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionner la fenêtre de l\'appli vers la droite"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Agrandir ou restaurer la taille de la fenêtre"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Passer en mode Écran partagé"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Activer le mode fenêtrage du bureau"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index aa2f6392842b..a2a6b3ebb2c4 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Controlador da aplicación"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona de aplicación"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pantalla completa"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modo de escritorio"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Pantalla dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Máis"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotante"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambiar a proporción"</string> <string name="close_text" msgid="4986518933445178928">"Pechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Pechar o menú"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menú"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Cambiar tamaño"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Non se pode mover aquí a aplicación"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Axustar o tamaño da ventá da aplicación á esquerda"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Axustar o tamaño da ventá da aplicación á dereita"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizar ou restaurar o tamaño da ventá"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entrar no modo de pantalla dividida"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entrar no modo de ventás do ordenador"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Axustar o tamaño da ventá á esquerda"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Axustar o tamaño da ventá á dereita"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamaño da ventá"</string> diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml index dcd57385809f..196784b29884 100644 --- a/libs/WindowManager/Shell/res/values-gu/strings.xml +++ b/libs/WindowManager/Shell/res/values-gu/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"ઍપનું હૅન્ડલ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ઍપનું આઇકન"</string> <string name="fullscreen_text" msgid="1162316685217676079">"પૂર્ણસ્ક્રીન"</string> - <string name="desktop_text" msgid="1077633567027630454">"ડેસ્કટૉપ મોડ"</string> + <string name="desktop_text" msgid="1582173066857454541">"ડેસ્કટૉપ વ્યૂ"</string> <string name="split_screen_text" msgid="1396336058129570886">"સ્ક્રીનને વિભાજિત કરો"</string> <string name="more_button_text" msgid="3655388105592893530">"વધુ"</string> <string name="float_button_text" msgid="9221657008391364581">"ફ્લોટિંગ વિન્ડો"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"સાપેક્ષ ગુણોત્તર બદલો"</string> <string name="close_text" msgid="4986518933445178928">"બંધ કરો"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"મેનૂ બંધ કરો"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"મેનૂ ખોલો"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ડેસ્કટૉપ વ્યૂ)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"સ્ક્રીન કરો મોટી કરો"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"કદ બદલો"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ઍપ અહીં ખસેડી શકાતી નથી"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ડાબી બાજુથી ઍપની વિન્ડોનું કદ બદલો"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"જમણી બાજુથી ઍપની વિન્ડોનું કદ બદલો"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"વિન્ડોનું કદ મહત્તમ કરો અથવા રિસ્ટોર કરો"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"સ્ક્રીન-વિભાજન મોડ દાખલ કરો"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ડેસ્કટૉપ વિન્ડો મોડ દાખલ કરો"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"મેનૂ ખોલો"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"<xliff:g id="WINDOWING_MODE">%1$s</xliff:g> દાખલ કરો"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ડાબી બાજુ વિન્ડોનું કદ બદલો"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"જમણી બાજુ વિન્ડોનું કદ બદલો"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"વિન્ડોનું કદ મહત્તમ કરો અથવા રિસ્ટોર કરો"</string> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index 4bf2d92c1860..f1f2a0ae8a9d 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"ऐप्लिकेशन का हैंडल"</string> <string name="app_icon_text" msgid="2823268023931811747">"ऐप्लिकेशन आइकॉन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फ़ुलस्क्रीन"</string> - <string name="desktop_text" msgid="1077633567027630454">"डेस्कटॉप मोड"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रीन मोड"</string> <string name="more_button_text" msgid="3655388105592893530">"ज़्यादा देखें"</string> <string name="float_button_text" msgid="9221657008391364581">"फ़्लोट"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) बदलें"</string> <string name="close_text" msgid="4986518933445178928">"बंद करें"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेन्यू बंद करें"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेन्यू खोलें"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन को बड़ा करें"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"साइज़ बदलें"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ऐप्लिकेशन को यहां मूव नहीं किया जा सकता"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ऐप्लिकेशन विंडो का साइज़ बाईं ओर से बदलें"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ऐप्लिकेशन विंडो का साइज़ दाईं ओर से बदलें"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रीन मोड में चालू करें"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटॉप विंडो मोड में जाएं"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विंडो का साइज़ बाईं ओर से बदलें"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विंडो का साइज़ दाईं ओर से बढ़ाएं"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string> diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml index 157822c5dc4f..b1187dc089b7 100644 --- a/libs/WindowManager/Shell/res/values-hr/strings.xml +++ b/libs/WindowManager/Shell/res/values-hr/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Pokazivač aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Puni zaslon"</string> - <string name="desktop_text" msgid="1077633567027630454">"Stolni način rada"</string> + <string name="desktop_text" msgid="1582173066857454541">"Prikaz na računalu"</string> <string name="split_screen_text" msgid="1396336058129570886">"Razdvojeni zaslon"</string> <string name="more_button_text" msgid="3655388105592893530">"Više"</string> <string name="float_button_text" msgid="9221657008391364581">"Plutajući"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Promijeni omjer slike"</string> <string name="close_text" msgid="4986518933445178928">"Zatvorite"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zatvorite izbornik"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvaranje izbornika"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (prikaz na računalu)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimalno povećaj zaslon"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Promijeni veličinu"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacija se ne može premjestiti ovdje"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Promijeni veličinu prozora aplikacije ulijevo"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Promijeni veličinu prozora aplikacije udesno"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimiziraj ili vrati veličinu prozora"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Pokreni način podijeljenog zaslona"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Pokreni način prikaza u prozorima na računalu"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Otvorite izbornik"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Unesite <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promijeni veličinu prozora ulijevo"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promijeni veličinu prozora udesno"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziraj ili vrati veličinu prozora"</string> diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml index 546a465c8699..5d52c4836e00 100644 --- a/libs/WindowManager/Shell/res/values-hu/strings.xml +++ b/libs/WindowManager/Shell/res/values-hu/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"App fogópontja"</string> <string name="app_icon_text" msgid="2823268023931811747">"Alkalmazásikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Teljes képernyő"</string> - <string name="desktop_text" msgid="1077633567027630454">"Asztali üzemmód"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Osztott képernyő"</string> <string name="more_button_text" msgid="3655388105592893530">"Továbbiak"</string> <string name="float_button_text" msgid="9221657008391364581">"Lebegő"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Méretarány módosítása"</string> <string name="close_text" msgid="4986518933445178928">"Bezárás"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menü bezárása"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menü megnyitása"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Képernyő méretének maximalizálása"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Átméretezés"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Az alkalmazás nem helyezhető át ide"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Alkalmazásablak átméretezése balra"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Alkalmazásablak átméretezése jobbra"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Ablak teljes méretre állítása vagy visszaállítása"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Belépés osztott képernyős módba"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Asztali ablakkezelési mód indítása"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ablak átméretezése balra"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ablak átméretezése jobbra"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ablak teljes méretre állítása vagy visszaállítása"</string> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index 39a395f9add1..b7b4422a673e 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Հավելվածի կեղծանուն"</string> <string name="app_icon_text" msgid="2823268023931811747">"Հավելվածի պատկերակ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Լիաէկրան"</string> - <string name="desktop_text" msgid="1077633567027630454">"Համակարգչի ռեժիմ"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Տրոհված էկրան"</string> <string name="more_button_text" msgid="3655388105592893530">"Ավելին"</string> <string name="float_button_text" msgid="9221657008391364581">"Լողացող պատուհան"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Փոխել կողմերի հարաբերակցությունը"</string> <string name="close_text" msgid="4986518933445178928">"Փակել"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Փակել ընտրացանկը"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Բացել ընտրացանկը"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ծավալել էկրանը"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Փոխել չափը"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Հավելվածը հնարավոր չէ տեղափոխել այստեղ"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ձգել հավելվածի պատուհանը դեպի ձախ"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ձգել հավելվածի պատուհանը դեպի աջ"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Մտնել էկրանի տրոհման ռեժիմ"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Մտնել համակարգչի ռեժիմ"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ձգել պատուհանը դեպի ձախ"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ձգել պատուհանը դեպի աջ"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index 09ce5257c56e..a3ed7c374355 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Penanganan aplikasi"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikon Aplikasi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Layar Penuh"</string> - <string name="desktop_text" msgid="1077633567027630454">"Mode Desktop"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Layar Terpisah"</string> <string name="more_button_text" msgid="3655388105592893530">"Lainnya"</string> <string name="float_button_text" msgid="9221657008391364581">"Mengambang"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ubah rasio aspek"</string> <string name="close_text" msgid="4986518933445178928">"Tutup"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buka Menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Perbesar Layar"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ubah ukuran"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikasi tidak dapat dipindahkan ke sini"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ubah ukuran jendela aplikasi ke kiri"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ubah ukuran jendela aplikasi ke kanan"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimalkan atau pulihkan ukuran jendela"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Masuk ke mode layar terpisah"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masuk ke mode windowing desktop"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ubah ukuran jendela ke kiri"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ubah ukuran jendela ke kanan"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimalkan atau pulihkan ukuran jendela"</string> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index 61c1d0e7759c..e8ecad1fc5e9 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Handfang forrits"</string> <string name="app_icon_text" msgid="2823268023931811747">"Tákn forrits"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Allur skjárinn"</string> - <string name="desktop_text" msgid="1077633567027630454">"Skjáborðsstilling"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Skjáskipting"</string> <string name="more_button_text" msgid="3655388105592893530">"Meira"</string> <string name="float_button_text" msgid="9221657008391364581">"Reikult"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Breyta myndhlutfalli"</string> <string name="close_text" msgid="4986518933445178928">"Loka"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Loka valmynd"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Opna valmynd"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Stækka skjá"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Breyta stærð"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ekki er hægt að færa forritið hingað"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Breyta stærð forritsglugga til vinstri"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Breyta stærð forritsglugga til hægri"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Hámarka eða endurheimta stærð glugga"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Skipta skjánum"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Opna gluggastillingu í tölvu"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Breyta stærð glugga til vinstri"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Breyta stærð glugga til hægri"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Hámarka eða endurheimta stærð glugga"</string> diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml index fab259e03b3b..630e9ee0f4f5 100644 --- a/libs/WindowManager/Shell/res/values-it/strings.xml +++ b/libs/WindowManager/Shell/res/values-it/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Punto di manipolazione app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icona dell\'app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Schermo intero"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modalità desktop"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Schermo diviso"</string> <string name="more_button_text" msgid="3655388105592893530">"Altro"</string> <string name="float_button_text" msgid="9221657008391364581">"Mobile"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Cambia proporzioni"</string> <string name="close_text" msgid="4986518933445178928">"Chiudi"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Chiudi il menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Apri il menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Massimizza schermo"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ridimensiona"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Impossibile spostare l\'app qui"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ridimensiona la finestra dell\'app a sinistra"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ridimensiona la finestra dell\'app a destra"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Ingrandisci o ripristina le dimensioni della finestra"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Attiva la modalità schermo diviso"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Attiva la modalità finestre del desktop"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ridimensiona la finestra a sinistra"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ridimensiona la finestra a destra"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ingrandisci o ripristina le dimensioni della finestra"</string> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index b164b1131ad2..102d646eb2b3 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"נקודת אחיזה לאפליקציה"</string> <string name="app_icon_text" msgid="2823268023931811747">"סמל האפליקציה"</string> <string name="fullscreen_text" msgid="1162316685217676079">"מסך מלא"</string> - <string name="desktop_text" msgid="1077633567027630454">"ממשק המחשב"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"מסך מפוצל"</string> <string name="more_button_text" msgid="3655388105592893530">"עוד"</string> <string name="float_button_text" msgid="9221657008391364581">"בלונים"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"שינוי יחס הגובה-רוחב"</string> <string name="close_text" msgid="4986518933445178928">"סגירה"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"סגירת התפריט"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"פתיחת התפריט"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"הגדלת המסך"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"שינוי הגודל"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"לא ניתן להעביר את האפליקציה לכאן"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"שינוי הגודל של חלון האפליקציה שמשמאל"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"שינוי הגודל של חלון האפליקציה שמימין"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"שחזור של גודל החלון או הגדלת החלון"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"כניסה למצב מסך מפוצל"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"כניסה למצב שינוי הגודל של החלונות בממשק המחשב"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"שינוי גודל החלון שמשמאל"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"שינוי גודל החלון שמימין"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"שחזור של גודל החלון או הגדלת החלון"</string> diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml index 3fe2a515437f..ac0df9c0b1cb 100644 --- a/libs/WindowManager/Shell/res/values-ja/strings.xml +++ b/libs/WindowManager/Shell/res/values-ja/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"アプリハンドル"</string> <string name="app_icon_text" msgid="2823268023931811747">"アプリのアイコン"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全画面表示"</string> - <string name="desktop_text" msgid="1077633567027630454">"デスクトップ モード"</string> + <string name="desktop_text" msgid="1582173066857454541">"デスクトップ ビュー"</string> <string name="split_screen_text" msgid="1396336058129570886">"分割画面"</string> <string name="more_button_text" msgid="3655388105592893530">"その他"</string> <string name="float_button_text" msgid="9221657008391364581">"フローティング"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"アスペクト比を変更"</string> <string name="close_text" msgid="4986518933445178928">"閉じる"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"メニューを閉じる"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"メニューを開く"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g>(デスクトップ ビュー)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"画面の最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"サイズ変更"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"アプリはここに移動できません"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"アプリ ウィンドウを左側にサイズ変更する"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"アプリ ウィンドウを右側にサイズ変更する"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ウィンドウを最大化する、またはウィンドウを元のサイズに戻す"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"分割画面モードに切り替える"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"デスクトップ ウィンドウ モードに切り替える"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"メニューを開く"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"<xliff:g id="WINDOWING_MODE">%1$s</xliff:g>に切り替え"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ウィンドウを左側にサイズ変更する"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ウィンドウを右側にサイズ変更する"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ウィンドウを最大化する、またはウィンドウを元のサイズに戻す"</string> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 1be19af9b372..84fab6fe22e6 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"აპის იდენტიფიკატორი"</string> <string name="app_icon_text" msgid="2823268023931811747">"აპის ხატულა"</string> <string name="fullscreen_text" msgid="1162316685217676079">"სრულ ეკრანზე"</string> - <string name="desktop_text" msgid="1077633567027630454">"დესკტოპის რეჟიმი"</string> + <string name="desktop_text" msgid="1582173066857454541">"დესკტოპის ხედი"</string> <string name="split_screen_text" msgid="1396336058129570886">"ეკრანის გაყოფა"</string> <string name="more_button_text" msgid="3655388105592893530">"სხვა"</string> <string name="float_button_text" msgid="9221657008391364581">"ფარფატი"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"თანაფარდობის შეცვლა"</string> <string name="close_text" msgid="4986518933445178928">"დახურვა"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"მენიუს დახურვა"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"მენიუს გახსნა"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (დესკტოპის ხედი)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"აპლიკაციის გაშლა სრულ ეკრანზე"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ზომის შეცვლა"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"აპის აქ გადატანა შეუძლებელია"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"აპის მარცხენა ფანჯრის ზომის შეცვლა"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"აპის მარჯვენა ფანჯრის ზომის შეცვლა"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"გაყოფილი ეკრანის რეჟიმში შესვლა"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"დესკტოპის ფანჯრის რეჟიმში შესვლა"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"მენიუს გახსნა"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"შეიყვანეთ <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ფანჯრის ზომის შეცვლა მარცხნივ"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ფანჯრის ზომის შეცვლა მარჯვნივ"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 5bd85191ec65..31a015333096 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Қолданба идентификаторы"</string> <string name="app_icon_text" msgid="2823268023931811747">"Қолданба белгішесі"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Толық экран"</string> - <string name="desktop_text" msgid="1077633567027630454">"Компьютер режимі"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Экранды бөлу"</string> <string name="more_button_text" msgid="3655388105592893530">"Қосымша"</string> <string name="float_button_text" msgid="9221657008391364581">"Қалқыма"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Арақатынасты өзгерту"</string> <string name="close_text" msgid="4986518933445178928">"Жабу"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Мәзірді жабу"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Мәзірді ашу"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды ұлғайту"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Өлшемін өзгерту"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Қолданба бұл жерге қойылмайды."</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Қолданба терезесінің өлшемін сол жақтан өзгерту"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Қолданба терезесінің өлшемін оң жақтан өзгерту"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Терезе өлшемін ұлғайту не қалпына келтіру"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Экранды бөлу режиміне өту"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Жұмыс үстелінің терезе режиміне өту"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезе өлшемін сол жаққа өзгерту"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезе өлшемін оң жаққа өзгерту"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезе өлшемін ұлғайту не қалпына келтіру"</string> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index f5118972d93f..9a7db6778162 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"ឈ្មោះអ្នកប្រើប្រាស់កម្មវិធី"</string> <string name="app_icon_text" msgid="2823268023931811747">"រូបកម្មវិធី"</string> <string name="fullscreen_text" msgid="1162316685217676079">"អេក្រង់ពេញ"</string> - <string name="desktop_text" msgid="1077633567027630454">"មុខងារកុំព្យូទ័រ"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"មុខងារបំបែកអេក្រង់"</string> <string name="more_button_text" msgid="3655388105592893530">"ច្រើនទៀត"</string> <string name="float_button_text" msgid="9221657008391364581">"អណ្ដែត"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ប្ដូរសមាមាត្រ"</string> <string name="close_text" msgid="4986518933445178928">"បិទ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"បិទម៉ឺនុយ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"បើកម៉ឺនុយ"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ពង្រីកអេក្រង់"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ប្ដូរទំហំ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"មិនអាចផ្លាស់ទីកម្មវិធីមកទីនេះបានទេ"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ប្ដូរទំហំវិនដូកម្មវិធីទៅឆ្វេង"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ប្ដូរទំហំវិនដូកម្មវិធីទៅស្ដាំ"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ស្ដារ ឬបង្កើនទំហំវិនដូជាអតិបរមា"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ចូលទៅមុខងារបំបែកអេក្រង់"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ចូលទៅមុខងារវិនដូកុំព្យូទ័រ"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ប្ដូរទំហំវិនដូទៅឆ្វេង"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ប្ដូរទំហំវិនដូទៅស្ដាំ"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ស្ដារ ឬបង្កើនទំហំវិនដូជាអតិបរមា"</string> diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml index 3bd5527a9fe5..e9fa2cf6aaa5 100644 --- a/libs/WindowManager/Shell/res/values-kn/strings.xml +++ b/libs/WindowManager/Shell/res/values-kn/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"ಆ್ಯಪ್ ಹ್ಯಾಂಡಲ್"</string> <string name="app_icon_text" msgid="2823268023931811747">"ಆ್ಯಪ್ ಐಕಾನ್"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ಫುಲ್ಸ್ಕ್ರೀನ್"</string> - <string name="desktop_text" msgid="1077633567027630454">"ಡೆಸ್ಕ್ಟಾಪ್ ಮೋಡ್"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string> <string name="more_button_text" msgid="3655388105592893530">"ಇನ್ನಷ್ಟು"</string> <string name="float_button_text" msgid="9221657008391364581">"ಫ್ಲೋಟ್"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ದೃಶ್ಯಾನುಪಾತವನ್ನು ಬದಲಾಯಿಸಿ"</string> <string name="close_text" msgid="4986518933445178928">"ಮುಚ್ಚಿ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ಮೆನು ಮುಚ್ಚಿ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ಮೆನು ತೆರೆಯಿರಿ"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ಸ್ಕ್ರೀನ್ ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ಆ್ಯಪ್ ಅನ್ನು ಇಲ್ಲಿಗೆ ಸರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ಮರುಗಾತ್ರಗೊಳಿಸಿ ಆ್ಯಪ್ ವಿಂಡೋ ಎಡ"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ಮರುಗಾತ್ರಗೊಳಿಸಿ ಆ್ಯಪ್ ವಿಂಡೋ ಬಲ"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ವಿಂಡೋ ಗಾತ್ರವನ್ನು ಗರಿಷ್ಠಗೊಳಿಸಿ ಅಥವಾ ಮರುಸ್ಥಾಪಿಸಿ"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಮೋಡ್ಗೆ ಪ್ರವೇಶಿಸಿ"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ಡೆಸ್ಕ್ಟಾಪ್ ವಿಂಡೋಯಿಂಗ್ ಮೋಡ್ಗೆ ಪ್ರವೇಶಿಸಿ"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ಮರುಗಾತ್ರಗೊಳಿಸಿ ವಿಂಡೋವನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ಮರುಗಾತ್ರಗೊಳಿಸಿ ವಿಂಡೋವನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ವಿಂಡೋ ಗಾತ್ರವನ್ನು ಗರಿಷ್ಠಗೊಳಿಸಿ ಅಥವಾ ಮರುಸ್ಥಾಪಿಸಿ"</string> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index 65add57a9e6b..dcdbaba97166 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"앱 핸들"</string> <string name="app_icon_text" msgid="2823268023931811747">"앱 아이콘"</string> <string name="fullscreen_text" msgid="1162316685217676079">"전체 화면"</string> - <string name="desktop_text" msgid="1077633567027630454">"데스크톱 모드"</string> + <string name="desktop_text" msgid="1582173066857454541">"데스크톱 뷰"</string> <string name="split_screen_text" msgid="1396336058129570886">"화면 분할"</string> <string name="more_button_text" msgid="3655388105592893530">"더보기"</string> <string name="float_button_text" msgid="9221657008391364581">"플로팅"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"가로세로 비율 변경"</string> <string name="close_text" msgid="4986518933445178928">"닫기"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"메뉴 닫기"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"메뉴 열기"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g>(데스크톱 뷰)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"화면 최대화"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"크기 조절"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"앱을 여기로 이동할 수 없음"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"앱 창 크기 왼쪽으로 조절"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"앱 창 크기 오른쪽으로 조절"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"창 최대화 또는 크기 복원"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"화면 분할 모드 시작"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"데스크톱 창 모드 시작"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"메뉴 열기"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"<xliff:g id="WINDOWING_MODE">%1$s</xliff:g> 입력"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"창 크기 왼쪽으로 조절"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"창 크기 오른쪽으로 조절"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"창 최대화 또는 크기 복원"</string> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index 96c2226daf58..3716741ed61a 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Колдонмонун маркери"</string> <string name="app_icon_text" msgid="2823268023931811747">"Колдонмонун сүрөтчөсү"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Толук экран"</string> - <string name="desktop_text" msgid="1077633567027630454">"Компьютер режими"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Экранды бөлүү"</string> <string name="more_button_text" msgid="3655388105592893530">"Дагы"</string> <string name="float_button_text" msgid="9221657008391364581">"Калкыма"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Тараптардын катнашын өзгөртүү"</string> <string name="close_text" msgid="4986518933445178928">"Жабуу"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Менюну жабуу"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Менюну ачуу"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Экранды чоңойтуу"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Өлчөмүн өзгөртүү"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Колдонмону бул жерге жылдырууга болбойт"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Колдонмонун терезесинин өлчөмүн солго өзгөртүү"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Колдонмонун терезесинин өлчөмүн оңго өзгөртүү"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Экранды бөлүү режимине өтүү"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Иш тактанын терезелери режимине өтүү"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезенин өлчөмүн солго өзгөртүү"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезенин өлчөмүн оңго өзгөртүү"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index 9337efc92606..a1d9d297ffae 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"ຊື່ຜູ້ໃຊ້ແອັບ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ໄອຄອນແອັບ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ເຕັມຈໍ"</string> - <string name="desktop_text" msgid="1077633567027630454">"ໂໝດເດັສທັອບ"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"ແບ່ງໜ້າຈໍ"</string> <string name="more_button_text" msgid="3655388105592893530">"ເພີ່ມເຕີມ"</string> <string name="float_button_text" msgid="9221657008391364581">"ລອຍ"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ປ່ຽນອັດຕາສ່ວນຮູບ"</string> <string name="close_text" msgid="4986518933445178928">"ປິດ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ປິດເມນູ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ເປີດເມນູ"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ປັບຈໍໃຫຍ່ສຸດ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ປັບຂະໜາດ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ບໍ່ສາມາດຍ້າຍແອັບມາບ່ອນນີ້ໄດ້"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ປັບຂະໜາດໜ້າຈໍແອັບໄປທາງຊ້າຍ"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ປັບຂະໜາດໜ້າຈໍແອັບໄປທາງຂວາ"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ເຂົ້າສູ່ໂໝດແບ່ງໜ້າຈໍ"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ເຂົ້າສູ່ໂໝດໜ້າຈໍເດັສທັອບ"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ປັບຂະໜາດໜ້າຈໍໄປທາງຊ້າຍ"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ປັບຂະໜາດໜ້າຈໍໄປທາງຂວາ"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index ede25645c76c..7ebd43d19833 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Programos kreipinys"</string> <string name="app_icon_text" msgid="2823268023931811747">"Programos piktograma"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Visas ekranas"</string> - <string name="desktop_text" msgid="1077633567027630454">"Stalinio kompiuterio režimas"</string> + <string name="desktop_text" msgid="1582173066857454541">"Rodinio versija staliniams kompiuteriams"</string> <string name="split_screen_text" msgid="1396336058129570886">"Išskaidyto ekrano režimas"</string> <string name="more_button_text" msgid="3655388105592893530">"Daugiau"</string> <string name="float_button_text" msgid="9221657008391364581">"Slankusis langas"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Keisti kraštinių santykį"</string> <string name="close_text" msgid="4986518933445178928">"Uždaryti"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Uždaryti meniu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Atidaryti meniu"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ (rodinio versija staliniams kompiuteriams)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Išskleisti ekraną"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Pakeisti dydį"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Programos negalima perkelti čia"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Pakeisti programos lango dydį kairėje"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Pakeisti programos lango dydį dešinėje"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Padidinti arba atkurti lango dydį"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Išskaidyto ekrano režimo įjungimas"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Įjungti darbalaukio pateikimo lange režimą"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Atidaryti meniu"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Eiti į „<xliff:g id="WINDOWING_MODE">%1$s</xliff:g>“"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pakeisti lango dydį kairėje"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pakeisti lango dydį dešinėje"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Padidinti arba atkurti lango dydį"</string> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index 24a969bc8c1b..3fcbbe20cff3 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Lietotnes turis"</string> <string name="app_icon_text" msgid="2823268023931811747">"Lietotnes ikona"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pilnekrāna režīms"</string> - <string name="desktop_text" msgid="1077633567027630454">"Darbvirsmas režīms"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Sadalīt ekrānu"</string> <string name="more_button_text" msgid="3655388105592893530">"Vairāk"</string> <string name="float_button_text" msgid="9221657008391364581">"Peldošs"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mainīt malu attiecību"</string> <string name="close_text" msgid="4986518933445178928">"Aizvērt"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Aizvērt izvēlni"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Atvērt izvēlni"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizēt ekrānu"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Mainīt lielumu"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Lietotni nevar pārvietot šeit."</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Mainīt lietotnes loga lielumu uz kreiso pusi"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Mainīt lietotnes loga lielumu uz labo pusi"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimizēt vai atjaunot loga lielumu"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Ieslēgt ekrāna sadalīšanas režīmu"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Ieslēgt darbvirsmas logu režīmu"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Mainīt loga lielumu uz kreiso pusi"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Mainīt loga lielumu uz labo pusi"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizēt vai atjaunot loga lielumu"</string> diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml index f7177acc8681..76b62ec1b6cf 100644 --- a/libs/WindowManager/Shell/res/values-mk/strings.xml +++ b/libs/WindowManager/Shell/res/values-mk/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Прекар на апликацијата"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона на апликацијата"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Цел екран"</string> - <string name="desktop_text" msgid="1077633567027630454">"Режим за компјутер"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Поделен екран"</string> <string name="more_button_text" msgid="3655388105592893530">"Повеќе"</string> <string name="float_button_text" msgid="9221657008391364581">"Лебдечко"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени го соодносот"</string> <string name="close_text" msgid="4986518933445178928">"Затворете"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затворете го менито"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отвори го менито"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Максимизирај го екранот"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Промени ја гол."</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликацијата не може да се премести овде"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Променете ја големината на прозорецот на апликацијата одлево"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Променете ја големината на прозорецот на апликацијата оддесно"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Максимизирајте или вратете ја големината на прозорецот"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Влезете во „Режим на поделен екран“"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Влезете во „Режим со прозорци на работната површина“"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Променете ја големината на прозорецот налево"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Променете ја големината на прозорецот надесно"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Максимизирајте или вратете ја големината на прозорецот"</string> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index 89215b66ba01..d9d0cf9b96a9 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"ആപ്പ് ഹാൻഡിൽ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ആപ്പ് ഐക്കൺ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"പൂർണ്ണസ്ക്രീൻ"</string> - <string name="desktop_text" msgid="1077633567027630454">"ഡെസ്ക്ടോപ്പ് മോഡ്"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"സ്ക്രീൻ വിഭജനം"</string> <string name="more_button_text" msgid="3655388105592893530">"കൂടുതൽ"</string> <string name="float_button_text" msgid="9221657008391364581">"ഫ്ലോട്ട്"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"വീക്ഷണ അനുപാതം മാറ്റുക"</string> <string name="close_text" msgid="4986518933445178928">"അടയ്ക്കുക"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"മെനു അടയ്ക്കുക"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"മെനു തുറക്കുക"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"സ്ക്രീൻ വലുതാക്കുക"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"വലുപ്പം മാറ്റുക"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ആപ്പ് ഇവിടേക്ക് നീക്കാനാകില്ല"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ഇടത് ആപ്പ് വിൻഡോ വലുപ്പം മാറ്റുക"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"വലത് ആപ്പ് വിൻഡോ വലുപ്പം മാറ്റുക"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"വിന്ഡോ വലുപ്പം വലുതാക്കുക അല്ലെങ്കിൽ പഴയത് പുനഃസ്ഥാപിക്കുക"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"സ്പ്ലിറ്റ് സ്ക്രീൻ മോഡിൽ പ്രവേശിക്കുക"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ഡെസ്ക്ടോപ്പ് വിൻഡോയിംഗ് മോഡിൽ പ്രവേശിക്കുക"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ഇടത്തേക്ക് ആപ്പ് വിൻഡോ വലുപ്പം മാറ്റുക"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"വലത്തേക്ക് ആപ്പ് വിൻഡോ വലുപ്പം മാറ്റുക"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"വിന്ഡോ വലുപ്പം വലുതാക്കുക അല്ലെങ്കിൽ പഴയത് പുനഃസ്ഥാപിക്കുക"</string> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index b38026cc5445..875eceab05d8 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Аппын бариул"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aппын дүрс тэмдэг"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Бүтэн дэлгэц"</string> - <string name="desktop_text" msgid="1077633567027630454">"Дэлгэцийн горим"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Дэлгэцийг хуваах"</string> <string name="more_button_text" msgid="3655388105592893530">"Бусад"</string> <string name="float_button_text" msgid="9221657008391364581">"Хөвөгч"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Аспектын харьцааг өөрчлөх"</string> <string name="close_text" msgid="4986518933445178928">"Хаах"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Цэсийг хаах"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Цэсийг нээх"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Дэлгэцийг томруулах"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Хэмжээг өөрчлөх"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Аппыг ийш зөөх боломжгүй"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Аппын цонхны хэмжээг зүүн тал руу өөрчлөх"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Аппын цонхны хэмжээг баруун тал руу өөрчлөх"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Дэлгэц хуваах горимд орох"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Дэлгэцийн цонхны горимд орох"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Цонхны хэмжээг зүүн тал руу өөрчлөх"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Цонхны хэмжээг баруун тал руу өөрчлөх"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index d9c1d1f45a55..73c16e67302b 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"अॅपचे हँडल"</string> <string name="app_icon_text" msgid="2823268023931811747">"अॅप आयकन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फुलस्क्रीन"</string> - <string name="desktop_text" msgid="1077633567027630454">"डेस्कटॉप मोड"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रीन"</string> <string name="more_button_text" msgid="3655388105592893530">"आणखी"</string> <string name="float_button_text" msgid="9221657008391364581">"फ्लोट"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"आस्पेक्ट रेशो बदला"</string> <string name="close_text" msgid="4986518933445178928">"बंद करा"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेनू बंद करा"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेनू उघडा"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रीन मोठी करा"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"आकार बदला"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"अॅप इथे हलवू शकत नाही"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"अॅप विंडोचा डावीकडून आकार बदला"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"अॅप विंडोचा उजवीकडून आकार बदला"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रीन मोड एंटर करा"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटॉप विंडोइंग मोड एंटर करा"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"अॅप विंडोचा डावीकडे आकार बदला"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"अॅप विंडोचा उजवीकडे आकार बदला"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string> diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml index a54ef140c9a1..81e00c50db46 100644 --- a/libs/WindowManager/Shell/res/values-ms/strings.xml +++ b/libs/WindowManager/Shell/res/values-ms/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Pengendalian apl"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikon Apl"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Skrin penuh"</string> - <string name="desktop_text" msgid="1077633567027630454">"Mod Desktop"</string> + <string name="desktop_text" msgid="1582173066857454541">"Paparan Desktop"</string> <string name="split_screen_text" msgid="1396336058129570886">"Skrin Pisah"</string> <string name="more_button_text" msgid="3655388105592893530">"Lagi"</string> <string name="float_button_text" msgid="9221657008391364581">"Terapung"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tukar nisbah bidang"</string> <string name="close_text" msgid="4986518933445178928">"Tutup"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Tutup Menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buka Menu"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Paparan Desktop)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimumkan Skrin"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ubah saiz"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Apl tidak boleh dialihkan ke sini"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Butang kiri ubah saiz tetingkap apl"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Butang kanan ubah saiz tetingkap apl"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimumkan atau pulihkan saiz tetingkap"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Masuki mod skrin pisah"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masuki mod tetingkap desktop"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Buka Menu"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Masukkan <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ubah saiz tetingkap ke sebelah kiri"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ubah saiz tetingkap ke sebelah kanan"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimumkan atau pulihkan saiz tetingkap"</string> diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml index 1f4db6d9b872..be7cca53717e 100644 --- a/libs/WindowManager/Shell/res/values-my/strings.xml +++ b/libs/WindowManager/Shell/res/values-my/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"အက်ပ်သုံးသူအမည်"</string> <string name="app_icon_text" msgid="2823268023931811747">"အက်ပ်သင်္ကေတ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ဖန်သားပြင်အပြည့်"</string> - <string name="desktop_text" msgid="1077633567027630454">"ဒက်စ်တော့မုဒ်"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"မျက်နှာပြင် ခွဲ၍ပြသရန်"</string> <string name="more_button_text" msgid="3655388105592893530">"ပိုပြပါ"</string> <string name="float_button_text" msgid="9221657008391364581">"မျှောရန်"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"အချိုးအစား ပြောင်းရန်"</string> <string name="close_text" msgid="4986518933445178928">"ပိတ်ရန်"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"မီနူး ပိတ်ရန်"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"မီနူး ဖွင့်ရန်"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"စခရင်ကို ချဲ့မည်"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"အရွယ်ပြင်ရန်"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"အက်ပ်ကို ဤနေရာသို့ ရွှေ့၍မရပါ"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"အက်ပ်ဝင်းဒိုး ဘယ်ဘက်ကို အရွယ်ပြင်ရန်"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"အက်ပ်ဝင်းဒိုး ညာဘက်ကို အရွယ်ပြင်ရန်"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"မျက်နှာပြင်ခွဲပြခြင်းမုဒ်သို့ ဝင်ရန်"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ဒက်စ်တော့ ဝင်းဒိုးမုဒ်သို့ ဝင်ရန်"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ဝင်းဒိုးကို ဘယ်ဘက်သို့ အရွယ်ပြင်ရန်"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ဝင်းဒိုးကို ညာဘက်သို့ အရွယ်ပြင်ရန်"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index 586a50f74f0d..c213b7b7227a 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Apphåndtak"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullskjerm"</string> - <string name="desktop_text" msgid="1077633567027630454">"Skrivebordmodus"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Delt skjerm"</string> <string name="more_button_text" msgid="3655388105592893530">"Mer"</string> <string name="float_button_text" msgid="9221657008391364581">"Svevende"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Endre høyde/bredde-forholdet"</string> <string name="close_text" msgid="4986518933445178928">"Lukk"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Lukk menyen"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Åpne menyen"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimer skjermen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Endre størrelse"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Appen kan ikke flyttes hit"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Endre størrelsen på appvinduet til venstre"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Endre størrelsen på appvinduet til høyre"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimer eller gjenopprett størrelsen på vinduet"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Start modusen for delt skjerm"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Start vindusmodus for skrivebordet"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Endre størrelsen på vinduet til venstre"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Endre størrelsen på vinduet til høyre"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimer eller gjenopprett størrelsen på vinduet"</string> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index f66fb1d30359..e5f4cbebce8c 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"एपको ह्यान्डल"</string> <string name="app_icon_text" msgid="2823268023931811747">"एपको आइकन"</string> <string name="fullscreen_text" msgid="1162316685217676079">"फुल स्क्रिन"</string> - <string name="desktop_text" msgid="1077633567027630454">"डेस्कटप मोड"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"स्प्लिट स्क्रिन"</string> <string name="more_button_text" msgid="3655388105592893530">"थप"</string> <string name="float_button_text" msgid="9221657008391364581">"फ्लोट"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"एस्पेक्ट रेसियो परिवर्तन गर्नुहोस्"</string> <string name="close_text" msgid="4986518933445178928">"बन्द गर्नुहोस्"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"मेनु बन्द गर्नुहोस्"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"मेनु खोल्नुहोस्"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"स्क्रिन ठुलो बनाउनुहोस्"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"आकार बदल्नुहोस्"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"एप सारेर यहाँ ल्याउन सकिएन"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"एपको विन्डोको आकार बदलेर बायाँतिर लैजानुहोस्"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"एपको विन्डोको आकार बदलेर दायाँतिर लैजानुहोस्"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"स्प्लिट स्क्रिन मोड प्रयोग गर्नुहोस्"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"डेस्कटप विन्डोइङ मोड प्रयोग गर्नुहोस्"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विन्डोको आकार बदलेर बायाँतिर लैजानुहोस्"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विन्डोको आकार बदलेर दायाँतिर लैजानुहोस्"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index 20bc65abab18..8396b3e9deeb 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"App-handgreep"</string> <string name="app_icon_text" msgid="2823268023931811747">"App-icoon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Volledig scherm"</string> - <string name="desktop_text" msgid="1077633567027630454">"Desktopmodus"</string> + <string name="desktop_text" msgid="1582173066857454541">"Desktopweergave"</string> <string name="split_screen_text" msgid="1396336058129570886">"Gesplitst scherm"</string> <string name="more_button_text" msgid="3655388105592893530">"Meer"</string> <string name="float_button_text" msgid="9221657008391364581">"Zwevend"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Beeldverhouding wijzigen"</string> <string name="close_text" msgid="4986518933445178928">"Sluiten"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menu sluiten"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menu openen"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (desktopweergave)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Scherm maximaliseren"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Formaat aanpassen"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Kan de app niet hierheen verplaatsen"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Formaat van app-venster naar links aanpassen"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Formaat van app-venster naar rechts aanpassen"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Formaat van venster maximaliseren of herstellen"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Modus voor gesplitst scherm openen"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Modus voor desktopvensterfuncties openen"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Menu openen"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"<xliff:g id="WINDOWING_MODE">%1$s</xliff:g> openen"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Formaat van venster naar links aanpassen"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Formaat van venster naar rechts aanpassen"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Formaat van venster maximaliseren of herstellen"</string> diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml index edb520872d1f..182ea46d83c2 100644 --- a/libs/WindowManager/Shell/res/values-or/strings.xml +++ b/libs/WindowManager/Shell/res/values-or/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"ଆପର ହେଣ୍ଡେଲ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ଆପ ଆଇକନ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ପୂର୍ଣ୍ଣସ୍କ୍ରିନ"</string> - <string name="desktop_text" msgid="1077633567027630454">"ଡେସ୍କଟପ ମୋଡ"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ"</string> <string name="more_button_text" msgid="3655388105592893530">"ଅଧିକ"</string> <string name="float_button_text" msgid="9221657008391364581">"ଫ୍ଲୋଟ"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ଚଉଡ଼ା ଓ ଉଚ୍ଚତାର ଅନୁପାତ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string> <string name="close_text" msgid="4986518933445178928">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ମେନୁ ବନ୍ଦ କରନ୍ତୁ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ମେନୁ ଖୋଲନ୍ତୁ"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ସ୍କ୍ରିନକୁ ବଡ଼ କରନ୍ତୁ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ରିସାଇଜ କରନ୍ତୁ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ଆପକୁ ଏଠାକୁ ମୁଭ କରାଯାଇପାରିବ ନାହିଁ"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ଆପ ୱିଣ୍ଡୋ ରିସାଇଜ କରିବା ପାଇଁ ବାମ ବଟନ"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ଆପ ୱିଣ୍ଡୋ ରିସାଇଜ କରିବା ପାଇଁ ଡାହାଣ ବଟନ"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ମୋଡରେ ପ୍ରବେଶ କରନ୍ତୁ"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ଡେସ୍କଟପ ୱିଣ୍ଡୋଇଂ ମୋଡରେ ପ୍ରବେଶ କରନ୍ତୁ"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ବାମପଟକୁ ୱିଣ୍ଡୋ ରିସାଇଜ କରନ୍ତୁ"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ଡାହାଣପଟକୁ ୱିଣ୍ଡୋ ରିସାଇଜ କରନ୍ତୁ"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index 29de4c45217f..3bc730bc0043 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"ਐਪ ਹੈਂਡਲ"</string> <string name="app_icon_text" msgid="2823268023931811747">"ਐਪ ਪ੍ਰਤੀਕ"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ਪੂਰੀ-ਸਕ੍ਰੀਨ"</string> - <string name="desktop_text" msgid="1077633567027630454">"ਡੈਸਕਟਾਪ ਮੋਡ"</string> + <string name="desktop_text" msgid="1582173066857454541">"ਡੈਸਕਟਾਪ ਦ੍ਰਿਸ਼"</string> <string name="split_screen_text" msgid="1396336058129570886">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string> <string name="more_button_text" msgid="3655388105592893530">"ਹੋਰ"</string> <string name="float_button_text" msgid="9221657008391364581">"ਫ਼ਲੋਟ"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ਆਕਾਰ ਅਨੁਪਾਤ ਬਦਲੋ"</string> <string name="close_text" msgid="4986518933445178928">"ਬੰਦ ਕਰੋ"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ਮੀਨੂ ਬੰਦ ਕਰੋ"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"ਮੀਨੂ ਖੋਲ੍ਹੋ"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (ਡੈਸਕਟਾਪ ਦ੍ਰਿਸ਼)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ਸਕ੍ਰੀਨ ਦਾ ਆਕਾਰ ਵਧਾਓ"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ਆਕਾਰ ਬਦਲੋ"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ਐਪ ਨੂੰ ਇੱਥੇ ਨਹੀਂ ਲਿਜਾਇਆ ਜਾ ਸਕਦਾ"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ਐਪ ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਬਦਲ ਕੇ ਖੱਬੇ ਪਾਸੇ ਕਰੋ"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ਐਪ ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਬਦਲ ਕੇ ਸੱਜੇ ਪਾਸੇ ਕਰੋ"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਵਧਾਓ ਜਾਂ ਮੁੜ-ਬਹਾਲ ਕਰੋ"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਮੋਡ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ਡੈਸਕਟਾਪ ਵਿੰਡੋ ਮੋਡ ਵਿੱਚ ਦਾਖਲ ਹੋਵੋ"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"ਮੀਨੂ ਖੋਲ੍ਹੋ"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Enter <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਬਦਲ ਕੇ ਖੱਬੇ ਪਾਸੇ ਕਰੋ"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਬਦਲ ਕੇ ਸੱਜੇ ਪਾਸੇ ਕਰੋ"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਵਧਾਓ ਜਾਂ ਮੁੜ-ਬਹਾਲ ਕਰੋ"</string> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index 47ee80e6a4e8..9a1bf3321274 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Uchwyt aplikacji"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacji"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Pełny ekran"</string> - <string name="desktop_text" msgid="1077633567027630454">"Tryb pulpitu"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Podzielony ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Więcej"</string> <string name="float_button_text" msgid="9221657008391364581">"Pływające"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Zmień format obrazu"</string> <string name="close_text" msgid="4986518933445178928">"Zamknij"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zamknij menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otwórz menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksymalizuj ekran"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Zmień rozmiar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Nie można przenieść aplikacji tutaj"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Zmień rozmiar okna aplikacji po lewej"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Zmień rozmiar okna aplikacji po prawej"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Zmaksymalizuj lub przywróć rozmiar okna"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Włącz tryb podzielonego ekranu"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Włącz tryb okien na pulpicie"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Zmień rozmiar okna do lewej"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Zmień rozmiar okna do prawej"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Zmaksymalizuj lub przywróć rozmiar okna"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml index 0a3ea7011e1e..3e019ecabcbd 100644 --- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modo área de trabalho"</string> + <string name="desktop_text" msgid="1582173066857454541">"Versão para computadores"</string> <string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> <string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mudar a proporção"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menu"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (versão para computadores)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionar janela do app para a esquerda"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionar janela do app para a direita"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizar ou restaurar o tamanho da janela"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entrar no modo de tela dividida"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entrar no modo de janela do computador"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Abrir o menu"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Entrar no <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamanho da janela"</string> diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml index c9d196b922db..0ca0e8e40543 100644 --- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Indicador da app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone da app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ecrã inteiro"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modo de ambiente de trabalho"</string> + <string name="desktop_text" msgid="1582173066857454541">"Vista de computador"</string> <string name="split_screen_text" msgid="1396336058129570886">"Ecrã dividido"</string> <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> <string name="float_button_text" msgid="9221657008391364581">"Flutuar"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Alterar formato"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir menu"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (vista de computador)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar ecrã"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover a app para aqui"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionar janela da app para a esquerda"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionar janela da app para a direita"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizar ou restaurar tamanho da janela"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Aceder ao modo de ecrã dividido"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Aceder ao modo de janelas de computador"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Abrir menu"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Entrar no modo <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar tamanho da janela"</string> diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml index 0a3ea7011e1e..3e019ecabcbd 100644 --- a/libs/WindowManager/Shell/res/values-pt/strings.xml +++ b/libs/WindowManager/Shell/res/values-pt/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tela cheia"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modo área de trabalho"</string> + <string name="desktop_text" msgid="1582173066857454541">"Versão para computadores"</string> <string name="split_screen_text" msgid="1396336058129570886">"Tela dividida"</string> <string name="more_button_text" msgid="3655388105592893530">"Mais"</string> <string name="float_button_text" msgid="9221657008391364581">"Ponto flutuante"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Mudar a proporção"</string> <string name="close_text" msgid="4986518933445178928">"Fechar"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Fechar menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Abrir o menu"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (versão para computadores)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ampliar tela"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionar"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Não é possível mover o app para cá"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionar janela do app para a esquerda"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionar janela do app para a direita"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizar ou restaurar o tamanho da janela"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Entrar no modo de tela dividida"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Entrar no modo de janela do computador"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Abrir o menu"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Entrar no <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamanho da janela"</string> diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml index a3313b6496e0..f71d93b59120 100644 --- a/libs/WindowManager/Shell/res/values-ro/strings.xml +++ b/libs/WindowManager/Shell/res/values-ro/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Handle de aplicație"</string> <string name="app_icon_text" msgid="2823268023931811747">"Pictograma aplicației"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ecran complet"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modul desktop"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Ecran împărțit"</string> <string name="more_button_text" msgid="3655388105592893530">"Mai multe"</string> <string name="float_button_text" msgid="9221657008391364581">"Flotantă"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Schimbă raportul de dimensiuni"</string> <string name="close_text" msgid="4986518933445178928">"Închide"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Închide meniul"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Deschide meniul"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizează fereastra"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Redimensionează"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplicația nu poate fi mutată aici"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Redimensionează fereastra aplicației la stânga"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Redimensionează fereastra aplicației la dreapta"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximizează sau restabilește dimensiunea ferestrei"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Accesează modul ecran împărțit"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Accesează modul de windowing pe desktop"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionează fereastra la stânga"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionează fereastra la dreapta"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizează sau restabilește dimensiunea ferestrei"</string> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index 5b20b2bd6499..adc6f32e4a8e 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Обозначение приложения"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок приложения"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Полноэкранный режим"</string> - <string name="desktop_text" msgid="1077633567027630454">"Режим компьютера"</string> + <string name="desktop_text" msgid="1582173066857454541">"Версия для ПК"</string> <string name="split_screen_text" msgid="1396336058129570886">"Разделить экран"</string> <string name="more_button_text" msgid="3655388105592893530">"Ещё"</string> <string name="float_button_text" msgid="9221657008391364581">"Плавающее окно"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Изменить соотношение сторон"</string> <string name="close_text" msgid="4986518933445178928">"Закрыть"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрыть меню"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Открыть меню"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" (версия для ПК)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Развернуть на весь экран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Изменить размер"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Приложение нельзя сюда переместить"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Растянуть окно приложения влево"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Растянуть окно приложения вправо"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Развернуть окно или восстановить его размер"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Перейти в режим разделения экрана"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Перейти в режим компьютера"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Открыть меню"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Открыть в режиме \"<xliff:g id="WINDOWING_MODE">%1$s</xliff:g>\""</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Растянуть окно влево"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Растянуть окно вправо"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Развернуть окно или восстановить его размер"</string> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index f0ef1d1bc658..b7b286338f16 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"යෙදුම් හසුරුව"</string> <string name="app_icon_text" msgid="2823268023931811747">"යෙදුම් නිරූපකය"</string> <string name="fullscreen_text" msgid="1162316685217676079">"පූර්ණ තිරය"</string> - <string name="desktop_text" msgid="1077633567027630454">"ඩෙස්ක්ටොප් ප්රකාරය"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"බෙදුම් තිරය"</string> <string name="more_button_text" msgid="3655388105592893530">"තව"</string> <string name="float_button_text" msgid="9221657008391364581">"පාවෙන"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"දර්ශන අනුපාතය වෙනස් කරන්න"</string> <string name="close_text" msgid="4986518933445178928">"වසන්න"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"මෙනුව වසන්න"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"මෙනුව විවෘත කරන්න"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"තිරය උපරිම කරන්න"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ප්රතිප්රමාණය කරන්න"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"යෙදුම මෙතැනට ගෙන යා නොහැක"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"යෙදුම් කවුළුව වමට ප්රතිප්රමාණ කරන්න"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"යෙදුම් කවුළුව දකුණට ප්රතිප්රමාණ කරන්න"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"කවුළු ප්රමාණය උපරිම කරන්න හෝ ප්රතිසාධනය කරන්න"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"බෙදුම් තිර මාදිලියට ඇතුළු වන්න"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ඩෙස්ක්ටොප කවුළුකරණ මාදිලියට ඇතුළු වන්න"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"කවුළුව වමට ප්රතිප්රමාණ කරන්න"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"කවුළුව දකුණට ප්රතිප්රමාණ කරන්න"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"කවුළු ප්රමාණය උපරිම කරන්න හෝ ප්රතිසාධනය කරන්න"</string> diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml index 688c217b8d32..ede0cdda7ab5 100644 --- a/libs/WindowManager/Shell/res/values-sk/strings.xml +++ b/libs/WindowManager/Shell/res/values-sk/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Rukoväť aplikácie"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikácie"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celá obrazovka"</string> - <string name="desktop_text" msgid="1077633567027630454">"Režim počítača"</string> + <string name="desktop_text" msgid="1582173066857454541">"Zobrazenie v počítači"</string> <string name="split_screen_text" msgid="1396336058129570886">"Rozdelená obrazovka"</string> <string name="more_button_text" msgid="3655388105592893530">"Viac"</string> <string name="float_button_text" msgid="9221657008391364581">"Plávajúce"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Zmeniť pomer strán"</string> <string name="close_text" msgid="4986518933445178928">"Zavrieť"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zavrieť ponuku"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Otvoriť ponuku"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (zobrazenie v počítači)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximalizovať obrazovku"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Zmeniť veľkosť"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikácia sa sem nedá presunúť"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Zmeniť veľkosť okna aplikácie vľavo"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Zmeniť veľkosť okna aplikácie vpravo"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximalizovať alebo obnoviť veľkosť okna"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Spustiť režim rozdelenej obrazovky"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Prejsť na režim okien na pracovnej ploche"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Otvoriť ponuku"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Zadať <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Zmeniť veľkosť okna vľavo"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Zmeniť veľkosť okna vpravo"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximalizovať alebo obnoviť veľkosť okna"</string> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index 69eb3e311726..5f1f6efd92fc 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Celozaslonsko"</string> - <string name="desktop_text" msgid="1077633567027630454">"Namizni način"</string> + <string name="desktop_text" msgid="1582173066857454541">"Pogled za namizni računalnik"</string> <string name="split_screen_text" msgid="1396336058129570886">"Razdeljen zaslon"</string> <string name="more_button_text" msgid="3655388105592893530">"Več"</string> <string name="float_button_text" msgid="9221657008391364581">"Lebdeče"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Sprememba razmerja stranic"</string> <string name="close_text" msgid="4986518933445178928">"Zapri"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Zapri meni"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Odpri meni"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (pogled za namizni računalnik)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimiraj zaslon"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Spremeni velikost"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacije ni mogoče premakniti sem"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Sprememba velikosti okna aplikacije na levi"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Sprememba velikosti okna aplikacije na desni"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Povečava ali obnovitev velikosti okna"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Vklop načina razdeljenega zaslona"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Vklop načina prikaza v oknu na namizju"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Odpiranje menija"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Odpiranje pogleda <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Sprememba velikosti okna na levi"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Sprememba velikosti okna na desni"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Povečava ali obnovitev velikosti okna"</string> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index fcb0aa6559fa..ea26bc6a5a4c 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Emërtimi i aplikacionit"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ikona e aplikacionit"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Ekrani i plotë"</string> - <string name="desktop_text" msgid="1077633567027630454">"Modaliteti i desktopit"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Ekrani i ndarë"</string> <string name="more_button_text" msgid="3655388105592893530">"Më shumë"</string> <string name="float_button_text" msgid="9221657008391364581">"Pluskuese"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ndrysho raportin e pamjes"</string> <string name="close_text" msgid="4986518933445178928">"Mbyll"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Hap menynë"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizo ekranin"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ndrysho përmasat"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacioni nuk mund të zhvendoset këtu"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ndrysho përmasat e dritares së aplikacionit majtas"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ndrysho përmasat e dritares së aplikacionit djathtas"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maksimizo ose restauro madhësinë e dritares"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Hyr në modalitetin e ekranit të ndarë"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Hyr në modalitetin e dritareve në desktop"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ndrysho përmasat e dritares në të majtë"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ndrysho përmasat e dritares në të djathtë"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizo ose restauro madhësinë e dritares"</string> diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml index 6a2ffcdf8e89..ea7a1bb292f2 100644 --- a/libs/WindowManager/Shell/res/values-sr/strings.xml +++ b/libs/WindowManager/Shell/res/values-sr/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Идентификатор апликације"</string> <string name="app_icon_text" msgid="2823268023931811747">"Икона апликације"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Преко целог екрана"</string> - <string name="desktop_text" msgid="1077633567027630454">"Режим за рачунаре"</string> + <string name="desktop_text" msgid="1582173066857454541">"Приказ за рачунаре"</string> <string name="split_screen_text" msgid="1396336058129570886">"Подељени екран"</string> <string name="more_button_text" msgid="3655388105592893530">"Још"</string> <string name="float_button_text" msgid="9221657008391364581">"Плутајуће"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Промени размеру"</string> <string name="close_text" msgid="4986518933445178928">"Затворите"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Затворите мени"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Отворите мени"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (приказ за рачунаре)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Повећај екран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Промени величину"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Апликација не може да се премести овде"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Промените величину прозора апликације налево"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Промените величину прозора апликације надесно"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Увећајте или вратите величину прозора"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Уђите у режим подељеног екрана"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Уђите у режим прозора на рачунару"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Отворите Мени"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Унесите <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Промените величину прозора налево"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Промените величину прозора надесно"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Увећајте или вратите величину прозора"</string> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index a9df47650dad..f3e53d0ed0c8 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"Apphandtag"</string> <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Helskärm"</string> - <string name="desktop_text" msgid="1077633567027630454">"Datorläge"</string> + <string name="desktop_text" msgid="1582173066857454541">"Datorvy"</string> <string name="split_screen_text" msgid="1396336058129570886">"Delad skärm"</string> <string name="more_button_text" msgid="3655388105592893530">"Mer"</string> <string name="float_button_text" msgid="9221657008391364581">"Svävande"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ändra bildformat"</string> <string name="close_text" msgid="4986518933445178928">"Stäng"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Stäng menyn"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Öppna menyn"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (datorvy)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximera skärmen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ändra storlek"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Det går inte att flytta appen hit"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ändra storlek på appfönstret åt vänster"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ändra storlek på appfönstret åt höger"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Maximera eller återställ fönsterstorleken"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Starta läget för delad skärm"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Starta datorläget"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"Öppna menyn"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"Ange <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ändra storlek på fönstret åt vänster"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ändra storlek på fönstret åt höger"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximera eller återställ fönsterstorleken"</string> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index a3c9a0d3989c..51aacac5902c 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Utambulisho wa programu"</string> <string name="app_icon_text" msgid="2823268023931811747">"Aikoni ya Programu"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Skrini nzima"</string> - <string name="desktop_text" msgid="1077633567027630454">"Hali ya Kompyuta ya mezani"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Gawa Skrini"</string> <string name="more_button_text" msgid="3655388105592893530">"Zaidi"</string> <string name="float_button_text" msgid="9221657008391364581">"Inayoelea"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Badilisha uwiano"</string> <string name="close_text" msgid="4986518933445178928">"Funga"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Funga Menyu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Fungua Menyu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Panua Dirisha kwenye Skrini"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Badilisha ukubwa"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Imeshindwa kuhamishia programu hapa"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Badilisha ukubwa wa dirisha la programu kushoto"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Badilisha ukubwa wa dirisha la programu kulia"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Panua au urejeshe ukubwa wa dirisha"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Ingia katika hali ya skrini iliyogawanywa"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Ingia katika hali ya madirisha ya kompyuta ya mezani"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Badilisha ukubwa wa dirisha kushoto"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Badilisha ukubwa wa dirisha kulia"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Panua au urejeshe ukubwa wa dirisha"</string> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index b1b8c7ff2075..0c7206c0b9d8 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"ஆப்ஸ் ஹேண்டில்"</string> <string name="app_icon_text" msgid="2823268023931811747">"ஆப்ஸ் ஐகான்"</string> <string name="fullscreen_text" msgid="1162316685217676079">"முழுத்திரை"</string> - <string name="desktop_text" msgid="1077633567027630454">"டெஸ்க்டாப் பயன்முறை"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"திரையைப் பிரிக்கும்"</string> <string name="more_button_text" msgid="3655388105592893530">"கூடுதல் விருப்பத்தேர்வுகள்"</string> <string name="float_button_text" msgid="9221657008391364581">"மிதக்கும் சாளரம்"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"தோற்ற விகிதத்தை மாற்று"</string> <string name="close_text" msgid="4986518933445178928">"மூடும்"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"மெனுவை மூடும்"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"மெனுவைத் திறக்கும்"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"திரையைப் பெரிதாக்கு"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"அளவை மாற்று"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ஆப்ஸை இங்கே நகர்த்த முடியாது"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ஆப்ஸ் சாளரத்தின் இடதுபுறத்தில் அளவை மாற்றும்"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ஆப்ஸ் சாளரத்தின் வலதுபுறத்தில் அளவை மாற்றும்"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"திரைப் பிரிப்புப் பயன்முறையில் உள்நுழையும்"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"டெஸ்க்டாப் சாளரப் பயன்முறையில் உள்நுழையும்"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"சாளரத்தை இடதுபுறமாக அளவு மாற்றும்"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"சாளரத்தை வலதுபுறமாக அளவு மாற்றும்"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string> diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml index 932f831c537d..f7cf43ed520c 100644 --- a/libs/WindowManager/Shell/res/values-te/strings.xml +++ b/libs/WindowManager/Shell/res/values-te/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"యాప్ హ్యాండిల్"</string> <string name="app_icon_text" msgid="2823268023931811747">"యాప్ చిహ్నం"</string> <string name="fullscreen_text" msgid="1162316685217676079">"ఫుల్-స్క్రీన్"</string> - <string name="desktop_text" msgid="1077633567027630454">"డెస్క్టాప్ మోడ్"</string> + <string name="desktop_text" msgid="1582173066857454541">"డెస్క్టాప్ వీక్షణ"</string> <string name="split_screen_text" msgid="1396336058129570886">"స్ప్లిట్ స్క్రీన్"</string> <string name="more_button_text" msgid="3655388105592893530">"మరిన్ని"</string> <string name="float_button_text" msgid="9221657008391364581">"ఫ్లోట్"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"ఆకార నిష్పత్తిని మార్చండి"</string> <string name="close_text" msgid="4986518933445178928">"మూసివేయండి"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"మెనూను మూసివేయండి"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"మెనూను తెరవండి"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (డెస్క్టాప్ వీక్షణ)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"స్క్రీన్ సైజ్ను పెంచండి"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"సైజ్ మార్చండి"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"యాప్ను ఇక్కడకి తరలించడం సాధ్యం కాదు"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"యాప్ విండో ఎడమ వైపు సైజ్ మార్చండి"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"యాప్ విండో కుడి వైపు సైజ్ మార్చండి"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"విండో సైజ్ను మ్యాగ్జిమైజ్ చేయండి లేదా రీస్టోర్ చేయండి"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"స్ప్లిట్ స్క్రీన్ మోడ్ను ఉపయోగించండి"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"డెస్క్టాప్ విండోయింగ్ మోడ్ను ఎంటర్ చేయండి"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"మెనూను తెరవండి"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"<xliff:g id="WINDOWING_MODE">%1$s</xliff:g>ను ఎంటర్ చేయండి"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"విండో ఎడమ వైపునకు సైజ్ను మార్చండి"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"విండో కుడి వైపునకు సైజ్ను మార్చండి"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"విండో సైజ్ను మ్యాగ్జిమైజ్ చేయండి లేదా రీస్టోర్ చేయండి"</string> diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml index e157474d34fa..77cd2e28517b 100644 --- a/libs/WindowManager/Shell/res/values-th/strings.xml +++ b/libs/WindowManager/Shell/res/values-th/strings.xml @@ -119,7 +119,7 @@ <string name="handle_text" msgid="4419667835599523257">"แฮนเดิลแอป"</string> <string name="app_icon_text" msgid="2823268023931811747">"ไอคอนแอป"</string> <string name="fullscreen_text" msgid="1162316685217676079">"เต็มหน้าจอ"</string> - <string name="desktop_text" msgid="1077633567027630454">"โหมดเดสก์ท็อป"</string> + <string name="desktop_text" msgid="1582173066857454541">"มุมมองบนเดสก์ท็อป"</string> <string name="split_screen_text" msgid="1396336058129570886">"แยกหน้าจอ"</string> <string name="more_button_text" msgid="3655388105592893530">"เพิ่มเติม"</string> <string name="float_button_text" msgid="9221657008391364581">"ล่องลอย"</string> @@ -132,7 +132,7 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"เปลี่ยนสัดส่วนการแสดงผล"</string> <string name="close_text" msgid="4986518933445178928">"ปิด"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"ปิดเมนู"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"เปิดเมนู"</string> + <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (มุมมองบนเดสก์ท็อป)"</string> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"ขยายหน้าจอให้ใหญ่สุด"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"ปรับขนาด"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ย้ายแอปมาที่นี่ไม่ได้"</string> @@ -145,8 +145,8 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"ปรับขนาดหน้าต่างแอปไปทางซ้าย"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ปรับขนาดหน้าต่างแอปไปทางขวา"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ขยายหรือคืนค่าขนาดหน้าต่าง"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"เข้าสู่โหมดแยกหน้าจอ"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"เข้าสู่โหมดหน้าต่างเดสก์ท็อป"</string> + <string name="app_handle_chip_accessibility_announce" msgid="499881698947450536">"เปิดเมนู"</string> + <string name="app_handle_menu_accessibility_announce" msgid="7928858564852785398">"เข้าสู่ <xliff:g id="WINDOWING_MODE">%1$s</xliff:g>"</string> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ปรับขนาดหน้าต่างไปทางซ้าย"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ปรับขนาดหน้าต่างไปทางขวา"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ขยายหรือคืนค่าขนาดหน้าต่าง"</string> diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml index 7f2970453072..5787e10d1ad3 100644 --- a/libs/WindowManager/Shell/res/values-tl/strings.xml +++ b/libs/WindowManager/Shell/res/values-tl/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Handle ng app"</string> <string name="app_icon_text" msgid="2823268023931811747">"Icon ng App"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Fullscreen"</string> - <string name="desktop_text" msgid="1077633567027630454">"Desktop Mode"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Split Screen"</string> <string name="more_button_text" msgid="3655388105592893530">"Higit pa"</string> <string name="float_button_text" msgid="9221657008391364581">"Float"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Baguhin ang aspect ratio"</string> <string name="close_text" msgid="4986518933445178928">"Isara"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Isara ang Menu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Buksan ang Menu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"I-maximize ang Screen"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"I-resize"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Hindi mailipat dito ang app"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"I-resize pakaliwa ang window ng app"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"I-resize pakanan ang window ng app"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"I-maximize o i-restore ang laki ng window"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Pumunta sa split screen mode"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Pumunta sa desktop windowing mode"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"I-resize pakaliwa ang window"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"I-resize pakanan ang window"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"I-maximize o i-restore ang laki ng window"</string> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 6a5d1abebd25..28b2a7d314d1 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Uygulama tanıtıcısı"</string> <string name="app_icon_text" msgid="2823268023931811747">"Uygulama Simgesi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Tam Ekran"</string> - <string name="desktop_text" msgid="1077633567027630454">"Masaüstü Modu"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Bölünmüş Ekran"</string> <string name="more_button_text" msgid="3655388105592893530">"Daha Fazla"</string> <string name="float_button_text" msgid="9221657008391364581">"Havada Süzülen"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"En boy oranını değiştir"</string> <string name="close_text" msgid="4986518933445178928">"Kapat"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menüyü kapat"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menüyü aç"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranı Büyüt"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Yeniden boyutlandır"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Uygulama buraya taşınamıyor"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Uygulama penceresini sola yeniden boyutlandır"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Uygulama penceresini sağa yeniden boyutlandır"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Bölünmüş ekran moduna gir"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Masaüstü pencereleme moduna gir"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pencereyi sola yeniden boyutlandır"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pencereyi sağa yeniden boyutlandır"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index 7f4e91d5dfc5..f5693ca04f1e 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Дескриптор додатка"</string> <string name="app_icon_text" msgid="2823268023931811747">"Значок додатка"</string> <string name="fullscreen_text" msgid="1162316685217676079">"На весь екран"</string> - <string name="desktop_text" msgid="1077633567027630454">"Режим комп’ютера"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Розділити екран"</string> <string name="more_button_text" msgid="3655388105592893530">"Більше"</string> <string name="float_button_text" msgid="9221657008391364581">"Плаваюче вікно"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Змінити формат"</string> <string name="close_text" msgid="4986518933445178928">"Закрити"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Закрити меню"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Відкрити меню"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Розгорнути екран"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Змінити розмір"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Сюди не можна перемістити додаток"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Змінити розмір вікна додатка ліворуч"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Змінити розмір вікна додатка праворуч"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Розгорнути вікно або відновити його розмір"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Увімкнути режим розділення екрана"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Увімкнути режим вікон для комп’ютера"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Змінити розмір вікна ліворуч"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Змінити розмір вікна праворуч"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Розгорнути вікно або відновити його розмір"</string> diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml index f461d4077087..a801b5eb47b0 100644 --- a/libs/WindowManager/Shell/res/values-ur/strings.xml +++ b/libs/WindowManager/Shell/res/values-ur/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"ایپ ہینڈل"</string> <string name="app_icon_text" msgid="2823268023931811747">"ایپ کا آئیکن"</string> <string name="fullscreen_text" msgid="1162316685217676079">"مکمل اسکرین"</string> - <string name="desktop_text" msgid="1077633567027630454">"ڈیسک ٹاپ موڈ"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"اسپلٹ اسکرین"</string> <string name="more_button_text" msgid="3655388105592893530">"مزید"</string> <string name="float_button_text" msgid="9221657008391364581">"فلوٹ"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"تناسبی شرح کو تبدیل کریں"</string> <string name="close_text" msgid="4986518933445178928">"بند کریں"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"مینیو بند کریں"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"مینو کھولیں"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"اسکرین کو بڑا کریں"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"سائز تبدیل کریں"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"ایپ کو یہاں منتقل نہیں کیا جا سکتا"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"دائیں طرف ایپ ونڈو کا سائز تبدیل کریں"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"ایپ ونڈو کا سائز بائیں طرف تبدیل کریں"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"سپلٹ اسکرین موڈ میں داخل ہوں"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"ڈیسک ٹاپ ونڈو وضع میں داخل ہوں"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"دائیں طرف ونڈو کا سائز تبدیل کریں"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ونڈو کا سائز بائیں طرف تبدیل کریں"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index 7c6a2a20aa80..9fbbdc81fc8e 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Ilova identifikatori"</string> <string name="app_icon_text" msgid="2823268023931811747">"Ilova belgisi"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Butun ekran"</string> - <string name="desktop_text" msgid="1077633567027630454">"Desktop rejimi"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Ekranni ikkiga ajratish"</string> <string name="more_button_text" msgid="3655388105592893530">"Yana"</string> <string name="float_button_text" msgid="9221657008391364581">"Pufakli"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Tomonlar nisbatini oʻzgartirish"</string> <string name="close_text" msgid="4986518933445178928">"Yopish"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Menyuni yopish"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Menyuni ochish"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Ekranni yoyish"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Oʻlchamini oʻzgartirish"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Ilova bu yerga surilmaydi"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Ilova chap oynasi oʻlchamini oʻzgartirish"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Ilova oʻng oynasi oʻlchamini oʻzgartirish"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Oyna oʻlchamini kengaytirish yoki asliga qaytarish"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Ajratilgan ekran rejimiga kirish"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Kompyuter rejimiga kirish"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Oyna oʻlchamini chapga oʻzgartirish"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Oyna oʻlchamini oʻngga oʻzgartirish"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Oyna oʻlchamini kengaytirish yoki asliga qaytarish"</string> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index e7cacc345c2b..b40a4e63be2b 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Ô điều khiển ứng dụng"</string> <string name="app_icon_text" msgid="2823268023931811747">"Biểu tượng ứng dụng"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Toàn màn hình"</string> - <string name="desktop_text" msgid="1077633567027630454">"Chế độ máy tính"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Chia đôi màn hình"</string> <string name="more_button_text" msgid="3655388105592893530">"Tuỳ chọn khác"</string> <string name="float_button_text" msgid="9221657008391364581">"Nổi"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Thay đổi tỷ lệ khung hình"</string> <string name="close_text" msgid="4986518933445178928">"Đóng"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Đóng trình đơn"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Mở Trình đơn"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Mở rộng màn hình"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Đổi kích thước"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Không di chuyển được ứng dụng đến đây"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Đổi kích thước và chuyển cửa sổ ứng dụng sang trái"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Đổi kích thước và chuyển cửa sổ ứng dụng sang phải"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Phóng to hoặc khôi phục kích thước cửa sổ"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Mở chế độ chia đôi màn hình"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Mở chế độ cửa sổ trên máy tính"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Đổi kích thước và chuyển cửa sổ sang trái"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Đổi kích thước và chuyển cửa sổ sang phải"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Phóng to hoặc khôi phục kích thước cửa sổ"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index 562a0ee09bd6..45cd25bcc757 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"应用手柄"</string> <string name="app_icon_text" msgid="2823268023931811747">"应用图标"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全屏"</string> - <string name="desktop_text" msgid="1077633567027630454">"桌面模式"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"分屏"</string> <string name="more_button_text" msgid="3655388105592893530">"更多"</string> <string name="float_button_text" msgid="9221657008391364581">"悬浮"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"更改宽高比"</string> <string name="close_text" msgid="4986518933445178928">"关闭"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"关闭菜单"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"打开菜单"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"最大化屏幕"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"调整大小"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"无法将应用移至此处"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"调整应用窗口大小并贴靠左侧"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"调整应用窗口大小并贴靠右侧"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"将窗口最大化或恢复大小"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"进入分屏模式"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"进入桌面设备窗口化模式"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"调整窗口大小并贴靠左侧"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"调整窗口大小并贴靠右侧"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"将窗口最大化或恢复大小"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml index eecd9f21be57..d2c22da78ac0 100644 --- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"應用程式控點"</string> <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string> - <string name="desktop_text" msgid="1077633567027630454">"桌面模式"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"分割螢幕"</string> <string name="more_button_text" msgid="3655388105592893530">"更多"</string> <string name="float_button_text" msgid="9221657008391364581">"浮動"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更長寬比"</string> <string name="close_text" msgid="4986518933445178928">"關閉"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"打開選單"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"調整大小"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至這裡"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"調整左邊應用程式視窗大小"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"調整右邊應用程式視窗大小"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"將視窗放到最大或者還原視窗大小"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"進入分割螢幕模式"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"進入桌面視窗模式"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"將視窗移去左邊調整大小"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"將視窗移去右邊調整大小"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗放到最大或者還原視窗大小"</string> diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml index c157c193fa14..0984fadc9b54 100644 --- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"應用程式控制代碼"</string> <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string> <string name="fullscreen_text" msgid="1162316685217676079">"全螢幕"</string> - <string name="desktop_text" msgid="1077633567027630454">"電腦模式"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"分割畫面"</string> <string name="more_button_text" msgid="3655388105592893530">"更多"</string> <string name="float_button_text" msgid="9221657008391364581">"浮動"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"變更顯示比例"</string> <string name="close_text" msgid="4986518933445178928">"關閉"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"關閉選單"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"開啟選單"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"畫面最大化"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"調整大小"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"應用程式無法移至此處"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"調整應用程式視窗大小並向左貼齊"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"調整應用程式視窗大小並向右貼齊"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"將視窗最大化或還原大小"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"進入分割畫面模式"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"進入電腦視窗化模式"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"調整應用程式視窗大小並向左貼齊"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"調整應用程式視窗大小並向右貼齊"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗最大化或還原大小"</string> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index a7ba6d21234d..13f8ed16faaa 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -119,7 +119,8 @@ <string name="handle_text" msgid="4419667835599523257">"Inkomba ye-App"</string> <string name="app_icon_text" msgid="2823268023931811747">"Isithonjana Se-app"</string> <string name="fullscreen_text" msgid="1162316685217676079">"Isikrini esigcwele"</string> - <string name="desktop_text" msgid="1077633567027630454">"Imodi Yedeskithophu"</string> + <!-- no translation found for desktop_text (1582173066857454541) --> + <skip /> <string name="split_screen_text" msgid="1396336058129570886">"Hlukanisa isikrini"</string> <string name="more_button_text" msgid="3655388105592893530">"Okwengeziwe"</string> <string name="float_button_text" msgid="9221657008391364581">"Iflowuthi"</string> @@ -132,7 +133,8 @@ <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Shintsha ukubukeka kwesilinganiselo"</string> <string name="close_text" msgid="4986518933445178928">"Vala"</string> <string name="collapse_menu_text" msgid="7515008122450342029">"Vala Imenyu"</string> - <string name="desktop_mode_app_header_chip_text" msgid="6366422614991687237">"Vula Imenyu"</string> + <!-- no translation found for desktop_mode_app_header_chip_text (8300164817452574565) --> + <skip /> <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Khulisa Isikrini Sifike Ekugcineni"</string> <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Shintsha usayizi"</string> <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"I-app ayikwazi ukuhanjiswa lapha"</string> @@ -145,8 +147,10 @@ <string name="desktop_mode_a11y_action_snap_left" msgid="2932955411661734668">"Shintsha usayizi we-app yewindi ngakwesokunxele"</string> <string name="desktop_mode_a11y_action_snap_right" msgid="4577032451624261787">"Shintsha usayizi we-app yewindi ngakwesokudla"</string> <string name="desktop_mode_a11y_action_maximize_restore" msgid="8026037983417986686">"Khulisa noma buyisela usayizi wewindi"</string> - <string name="app_handle_menu_talkback_split_screen_mode_button_text" msgid="7182959681057464802">"Faka imodi yokuhlukanisa isikrini"</string> - <string name="app_handle_menu_talkback_desktop_mode_button_text" msgid="1230110046930843630">"Faka imodi yokwenza iwindi yedeskithophu"</string> + <!-- no translation found for app_handle_chip_accessibility_announce (499881698947450536) --> + <skip /> + <!-- no translation found for app_handle_menu_accessibility_announce (7928858564852785398) --> + <skip /> <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Shintsha usayizi wewindi ngakwesokunxele"</string> <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Shintsha usayizi wewindi ngakwesokudla"</string> <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Khulisa noma buyisela usayizi wewindi"</string> diff --git a/libs/WindowManager/Shell/shared/res/values/dimen.xml b/libs/WindowManager/Shell/shared/res/values/dimen.xml index 5f013c52d70d..11a6f32d7454 100644 --- a/libs/WindowManager/Shell/shared/res/values/dimen.xml +++ b/libs/WindowManager/Shell/shared/res/values/dimen.xml @@ -38,6 +38,7 @@ <dimen name="drag_zone_v_split_from_expanded_view_height_fold_short">100dp</dimen> <!-- Bubble drop target dimensions --> + <dimen name="drop_target_elevation">1dp</dimen> <dimen name="drop_target_full_screen_padding">20dp</dimen> <dimen name="drop_target_desktop_window_padding_small">100dp</dimen> <dimen name="drop_target_desktop_window_padding_large">130dp</dimen> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt index 5d346c047123..6eff75c9a479 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZone.kt @@ -31,29 +31,41 @@ sealed interface DragZone { /** The bounds of this drag zone. */ val bounds: Rect + /** The bounds of the drop target associated with this drag zone. */ + val dropTarget: Rect? fun contains(x: Int, y: Int) = bounds.contains(x, y) /** Represents the bubble drag area on the screen. */ - sealed class Bubble(override val bounds: Rect) : DragZone { - data class Left(override val bounds: Rect, val dropTarget: Rect) : Bubble(bounds) - data class Right(override val bounds: Rect, val dropTarget: Rect) : Bubble(bounds) + sealed class Bubble(override val bounds: Rect, override val dropTarget: Rect) : DragZone { + data class Left(override val bounds: Rect, override val dropTarget: Rect) : + Bubble(bounds, dropTarget) + + data class Right(override val bounds: Rect, override val dropTarget: Rect) : + Bubble(bounds, dropTarget) } /** Represents dragging to Desktop Window. */ - data class DesktopWindow(override val bounds: Rect, val dropTarget: Rect) : DragZone + data class DesktopWindow(override val bounds: Rect, override val dropTarget: Rect) : DragZone /** Represents dragging to Full Screen. */ - data class FullScreen(override val bounds: Rect, val dropTarget: Rect) : DragZone + data class FullScreen(override val bounds: Rect, override val dropTarget: Rect) : DragZone /** Represents dragging to dismiss. */ - data class Dismiss(override val bounds: Rect) : DragZone + data class Dismiss(override val bounds: Rect) : DragZone { + override val dropTarget: Rect? = null + } /** Represents dragging to enter Split or replace a Split app. */ sealed class Split(override val bounds: Rect) : DragZone { + override val dropTarget: Rect? = null + data class Left(override val bounds: Rect) : Split(bounds) + data class Right(override val bounds: Rect) : Split(bounds) + data class Top(override val bounds: Rect) : Split(bounds) + data class Bottom(override val bounds: Rect) : Split(bounds) } } diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt index 29ce8d90e66f..2dc183f3f707 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt @@ -16,22 +16,54 @@ package com.android.wm.shell.shared.bubbles +import android.content.Context +import android.graphics.Rect +import android.view.View +import android.widget.FrameLayout +import androidx.core.animation.Animator +import androidx.core.animation.AnimatorListenerAdapter +import androidx.core.animation.ValueAnimator + /** * Manages animating drop targets in response to dragging bubble icons or bubble expanded views * across different drag zones. */ class DropTargetManager( + context: Context, + private val container: FrameLayout, private val isLayoutRtl: Boolean, - private val dragZoneChangedListener: DragZoneChangedListener + private val dragZoneChangedListener: DragZoneChangedListener, ) { private var state: DragState? = null + private val dropTargetView = View(context) + private var animator: ValueAnimator? = null + + private companion object { + const val ANIMATION_DURATION_MS = 250L + } /** Must be called when a drag gesture is starting. */ fun onDragStarted(draggedObject: DraggedObject, dragZones: List<DragZone>) { val state = DragState(dragZones, draggedObject) dragZoneChangedListener.onInitialDragZoneSet(state.initialDragZone) this.state = state + animator?.cancel() + setupDropTarget() + } + + private fun setupDropTarget() { + if (dropTargetView.parent != null) container.removeView(dropTargetView) + container.addView(dropTargetView, 0) + // TODO b/393173014: set elevation and background + dropTargetView.alpha = 0f + dropTargetView.scaleX = 1f + dropTargetView.scaleY = 1f + dropTargetView.translationX = 0f + dropTargetView.translationY = 0f + // the drop target is added with a width and height of 1 pixel. when it gets resized, we use + // set its scale to the width and height of the bounds it should have to avoid layout passes + dropTargetView.layoutParams = FrameLayout.LayoutParams(/* width= */ 1, /* height= */ 1) } /** Called when the user drags to a new location. */ @@ -42,14 +74,67 @@ class DropTargetManager( state.currentDragZone = newDragZone if (oldDragZone != newDragZone) { dragZoneChangedListener.onDragZoneChanged(from = oldDragZone, to = newDragZone) + updateDropTarget() } } /** Called when the drag ended. */ fun onDragEnded() { + startFadeAnimation(from = dropTargetView.alpha, to = 0f) { + container.removeView(dropTargetView) + } state = null } + private fun updateDropTarget() { + val currentDragZone = state?.currentDragZone ?: return + val dropTargetBounds = currentDragZone.dropTarget + when { + dropTargetBounds == null -> startFadeAnimation(from = dropTargetView.alpha, to = 0f) + dropTargetView.alpha == 0f -> { + dropTargetView.translationX = dropTargetBounds.exactCenterX() + dropTargetView.translationY = dropTargetBounds.exactCenterY() + dropTargetView.scaleX = dropTargetBounds.width().toFloat() + dropTargetView.scaleY = dropTargetBounds.height().toFloat() + startFadeAnimation(from = 0f, to = 1f) + } + else -> startMorphAnimation(dropTargetBounds) + } + } + + private fun startFadeAnimation(from: Float, to: Float, onEnd: (() -> Unit)? = null) { + animator?.cancel() + val animator = ValueAnimator.ofFloat(from, to).setDuration(ANIMATION_DURATION_MS) + animator.addUpdateListener { _ -> dropTargetView.alpha = animator.animatedValue as Float } + if (onEnd != null) { + animator.doOnEnd(onEnd) + } + this.animator = animator + animator.start() + } + + private fun startMorphAnimation(bounds: Rect) { + animator?.cancel() + val startAlpha = dropTargetView.alpha + val startTx = dropTargetView.translationX + val startTy = dropTargetView.translationY + val startScaleX = dropTargetView.scaleX + val startScaleY = dropTargetView.scaleY + val animator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIMATION_DURATION_MS) + animator.addUpdateListener { _ -> + val fraction = animator.animatedValue as Float + dropTargetView.alpha = startAlpha + (1 - startAlpha) * fraction + dropTargetView.translationX = startTx + (bounds.exactCenterX() - startTx) * fraction + dropTargetView.translationY = startTy + (bounds.exactCenterY() - startTy) * fraction + dropTargetView.scaleX = + startScaleX + (bounds.width().toFloat() - startScaleX) * fraction + dropTargetView.scaleY = + startScaleY + (bounds.height().toFloat() - startScaleY) * fraction + } + this.animator = animator + animator.start() + } + /** Stores the current drag state. */ private inner class DragState( private val dragZones: List<DragZone>, @@ -72,7 +157,18 @@ class DropTargetManager( interface DragZoneChangedListener { /** An initial drag zone was set. Called when a drag starts. */ fun onInitialDragZoneSet(dragZone: DragZone) + /** Called when the object was dragged to a different drag zone. */ fun onDragZoneChanged(from: DragZone, to: DragZone) } + + private fun Animator.doOnEnd(onEnd: () -> Unit) { + addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + onEnd() + } + } + ) + } } diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt index 126ab3d74689..0e4a6b9fb083 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicy.kt @@ -16,15 +16,16 @@ package com.android.wm.shell.shared.desktopmode +import android.Manifest.permission.SYSTEM_ALERT_WINDOW import android.app.TaskInfo import android.content.Context import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED import android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION import android.content.pm.ActivityInfo.OVERRIDE_EXCLUDE_CAPTION_INSETS_FROM_APP_BOUNDS +import android.content.pm.PackageManager import android.window.DesktopModeFlags import com.android.internal.R -import com.android.window.flags.Flags /** * Class to decide whether to apply app compat policies in desktop mode. @@ -33,8 +34,10 @@ import com.android.window.flags.Flags class DesktopModeCompatPolicy(private val context: Context) { private val systemUiPackage: String = context.resources.getString(R.string.config_systemUi) + private val pkgManager: PackageManager + get() = context.getPackageManager() private val defaultHomePackage: String? - get() = context.getPackageManager().getHomeActivities(ArrayList())?.packageName + get() = pkgManager.getHomeActivities(ArrayList())?.packageName /** * If the top activity should be exempt from desktop windowing and forced back to fullscreen. @@ -48,11 +51,12 @@ class DesktopModeCompatPolicy(private val context: Context) { fun isTopActivityExemptFromDesktopWindowing(packageName: String?, numActivities: Int, isTopActivityNoDisplay: Boolean, isActivityStackTransparent: Boolean) = - DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue - && ((isSystemUiTask(packageName) - || isPartOfDefaultHomePackageOrNoHomeAvailable(packageName) - || isTransparentTask(isActivityStackTransparent, numActivities)) - && !isTopActivityNoDisplay) + DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue && + ((isSystemUiTask(packageName) || + isPartOfDefaultHomePackageOrNoHomeAvailable(packageName) || + (isTransparentTask(isActivityStackTransparent, numActivities) && + hasFullscreenTransparentPermission(packageName))) && + !isTopActivityNoDisplay) /** * Whether the caption insets should be excluded from configuration for system to handle. @@ -64,7 +68,7 @@ class DesktopModeCompatPolicy(private val context: Context) { * is enabled. */ fun shouldExcludeCaptionFromAppBounds(taskInfo: TaskInfo): Boolean = - Flags.excludeCaptionFromAppBounds() + DesktopModeFlags.EXCLUDE_CAPTION_FROM_APP_BOUNDS.isTrue && isAnyForceConsumptionFlagsEnabled() && taskInfo.topActivityInfo?.let { isInsetsCoupledWithConfiguration(it) && (!taskInfo.isResizeable || it.isChangeEnabled( @@ -84,6 +88,26 @@ class DesktopModeCompatPolicy(private val context: Context) { private fun isSystemUiTask(packageName: String?) = packageName == systemUiPackage + // Checks if the app for the given package has the SYSTEM_ALERT_WINDOW permission. + private fun hasFullscreenTransparentPermission(packageName: String?): Boolean { + if (DesktopModeFlags.ENABLE_MODALS_FULLSCREEN_WITH_PERMISSIONS.isTrue) { + if (packageName == null) { + return false + } + return try { + val packageInfo = pkgManager.getPackageInfo( + packageName, + PackageManager.GET_PERMISSIONS + ) + packageInfo?.requestedPermissions?.contains(SYSTEM_ALERT_WINDOW) == true + } catch (e: PackageManager.NameNotFoundException) { + false // Package not found + } + } + // If the flag is disabled we make this condition neutral. + return true + } + /** * Returns true if the tasks base activity is part of the default home package, or there is * currently no default home package available. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java index 5bd8d86f1144..0f1bf5e09751 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java @@ -15,6 +15,8 @@ */ package com.android.wm.shell.bubbles; +import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR; + import android.annotation.DrawableRes; import android.annotation.Nullable; import android.content.Context; @@ -35,7 +37,6 @@ import android.widget.ImageView; import androidx.constraintlayout.widget.ConstraintLayout; import com.android.launcher3.icons.DotRenderer; -import com.android.launcher3.icons.IconNormalizer; import com.android.wm.shell.R; import com.android.wm.shell.shared.animation.Interpolators; @@ -132,7 +133,7 @@ public class BadgedImageView extends ConstraintLayout { private void getOutline(Outline outline) { final int bubbleSize = mPositioner.getBubbleSize(); - final int normalizedSize = IconNormalizer.getNormalizedCircleSize(bubbleSize); + final int normalizedSize = Math.round(ICON_VISIBLE_AREA_FACTOR * bubbleSize); final int inset = (bubbleSize - normalizedSize) / 2; outline.setOval(inset, inset, inset + normalizedSize, inset + normalizedSize); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 58b46d202599..305fcdd5fb7d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -595,7 +595,10 @@ public class BubbleController implements ConfigurationChangeListener, * <p>If bubble bar is supported, bubble views will be updated to switch to bar mode. */ public void registerBubbleStateListener(Bubbles.BubbleStateListener listener) { - if (Flags.enableBubbleBar() && mBubblePositioner.isLargeScreen() && listener != null) { + final boolean bubbleBarAllowed = Flags.enableBubbleBar() + && (mBubblePositioner.isLargeScreen() || Flags.enableBubbleBarOnPhones()) + && listener != null; + if (bubbleBarAllowed) { // Only set the listener if we can show the bubble bar. mBubbleStateListener = listener; setUpBubbleViewsForMode(); @@ -772,7 +775,7 @@ public class BubbleController implements ConfigurationChangeListener, /** Whether bubbles would be shown with the bubble bar UI. */ public boolean isShowingAsBubbleBar() { return Flags.enableBubbleBar() - && mBubblePositioner.isLargeScreen() + && (mBubblePositioner.isLargeScreen() || Flags.enableBubbleBarOnPhones()) && mBubbleStateListener != null; } @@ -909,7 +912,7 @@ public class BubbleController implements ConfigurationChangeListener, // TODO(b/393172431) : Utilise DragZoneFactory once it is ready final int bubbleBarDropZoneSideSize = getContext().getResources().getDimensionPixelSize( R.dimen.bubble_bar_drop_zone_side_size); - int top = t - bubbleBarDropZoneSideSize; + int top = b - bubbleBarDropZoneSideSize; result.put(BubbleBarLocation.LEFT, new Rect(l, top, l + bubbleBarDropZoneSideSize, b)); result.put(BubbleBarLocation.RIGHT, 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 5273a7cf2432..33f1b94bac73 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 @@ -16,6 +16,7 @@ package com.android.wm.shell.bubbles; +import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES; import android.content.Context; @@ -31,7 +32,7 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.internal.protolog.ProtoLog; -import com.android.launcher3.icons.IconNormalizer; +import com.android.wm.shell.Flags; import com.android.wm.shell.R; import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import com.android.wm.shell.shared.bubbles.BubbleDropTargetBoundsProvider; @@ -556,8 +557,7 @@ public class BubblePositioner implements BubbleDropTargetBoundsProvider { public float getPointerPosition(float bubblePosition) { // TODO: I don't understand why it works but it does - why normalized in portrait // & not in landscape? Am I missing ~2dp in the portrait expandedViewY calculation? - final float normalizedSize = IconNormalizer.getNormalizedCircleSize( - getBubbleSize()); + final float normalizedSize = Math.round(ICON_VISIBLE_AREA_FACTOR * getBubbleSize()); return showBubblesVertically() ? bubblePosition + (getBubbleSize() / 2f) : bubblePosition + (normalizedSize / 2f) - mPointerWidth; @@ -906,7 +906,7 @@ public class BubblePositioner implements BubbleDropTargetBoundsProvider { if (isOverflow) { return mOverflowHeight; } else { - return getBubbleBarExpandedViewHeightForLandscape(); + return getBubbleBarExpandedViewHeight(); } } @@ -927,18 +927,23 @@ public class BubblePositioner implements BubbleDropTargetBoundsProvider { * | bottom inset ↕ | ↓ * |----------------------| --- mScreenRect.bottom */ - private int getBubbleBarExpandedViewHeightForLandscape() { + private int getBubbleBarExpandedViewHeight() { int heightOfBubbleBarContainer = mScreenRect.height() - getExpandedViewBottomForBubbleBar(); - // getting landscape height from screen rect - int expandedViewHeight = Math.min(mScreenRect.width(), mScreenRect.height()); + int expandedViewHeight; + if (Flags.enableBubbleBarOnPhones() && !mDeviceConfig.isLargeScreen()) { + // we're on a phone, use the max / height + expandedViewHeight = Math.max(mScreenRect.width(), mScreenRect.height()); + } else { + // getting landscape height from screen rect + expandedViewHeight = Math.min(mScreenRect.width(), mScreenRect.height()); + } expandedViewHeight -= heightOfBubbleBarContainer; /* removing bubble container height */ expandedViewHeight -= mInsets.top; /* removing top inset */ expandedViewHeight -= mExpandedViewPadding; /* removing spacing */ return expandedViewHeight; } - /** The bottom position of the expanded view when showing above the bubble bar. */ public int getExpandedViewBottomForBubbleBar() { return mBubbleBarTopOnScreen - mExpandedViewPadding; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java index e3b0872df593..29837dc04423 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java @@ -135,6 +135,7 @@ public class BubbleBarLayerView extends FrameLayout /** Shows the expanded view drop target at the requested {@link BubbleBarLocation location} */ public void showBubbleBarExtendedViewDropTarget(@NonNull BubbleBarLocation bubbleBarLocation) { + setVisibility(VISIBLE); mBubbleExpandedViewPinController.showDropTarget(bubbleBarLocation); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java index 8377a35a9e7d..87a4115ccd3a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java @@ -324,8 +324,10 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged } applyVisibilityToLeash(imeSourceControl); } - if (!mImeShowing) { - removeImeSurface(mDisplayId); + if (!android.view.inputmethod.Flags.refactorInsetsController()) { + if (!mImeShowing) { + removeImeSurface(mDisplayId); + } } } } else { @@ -663,7 +665,9 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged ImeTracker.forLogging().onProgress(mStatsToken, ImeTracker.PHASE_WM_ANIMATION_RUNNING); t.hide(animatingLeash); - removeImeSurface(mDisplayId); + if (!android.view.inputmethod.Flags.refactorInsetsController()) { + removeImeSurface(mDisplayId); + } if (android.view.inputmethod.Flags.refactorInsetsController()) { setVisibleDirectly(false /* visible */, statsToken); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorController.kt new file mode 100644 index 000000000000..7a5bc1383ccf --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorController.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.common + +import android.app.ActivityManager.RunningTaskInfo +import android.graphics.RectF +import android.view.SurfaceControl +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.shared.annotations.ShellDesktopThread + +/** + * Controller to manage the indicators that show users the current position of the dragged window on + * the new display when performing drag move across displays. + */ +class MultiDisplayDragMoveIndicatorController( + private val displayController: DisplayController, + private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, + private val indicatorSurfaceFactory: MultiDisplayDragMoveIndicatorSurface.Factory, + @ShellDesktopThread private val desktopExecutor: ShellExecutor, +) { + @ShellDesktopThread + private val dragIndicators = + mutableMapOf<Int, MutableMap<Int, MultiDisplayDragMoveIndicatorSurface>>() + + /** + * Called during drag move, which started at [startDisplayId]. Updates the position and + * visibility of the drag move indicators for the [taskInfo] based on [boundsDp] on the + * destination displays ([displayIds]) as the dragged window moves. [transactionSupplier] + * provides a [SurfaceControl.Transaction] for applying changes to the indicator surfaces. + * + * It is executed on the [desktopExecutor] to prevent blocking the main thread and avoid jank, + * as creating and manipulating surfaces can be expensive. + */ + fun onDragMove( + boundsDp: RectF, + startDisplayId: Int, + taskInfo: RunningTaskInfo, + displayIds: Set<Int>, + transactionSupplier: () -> SurfaceControl.Transaction, + ) { + desktopExecutor.execute { + for (displayId in displayIds) { + if (displayId == startDisplayId) { + // No need to render indicators on the original display where the drag started. + continue + } + val displayLayout = displayController.getDisplayLayout(displayId) ?: continue + val shouldBeVisible = + RectF.intersects(RectF(boundsDp), displayLayout.globalBoundsDp()) + if ( + dragIndicators[taskInfo.taskId]?.containsKey(displayId) != true && + !shouldBeVisible + ) { + // Skip this display if: + // - It doesn't have an existing indicator that needs to be updated, AND + // - The latest dragged window bounds don't intersect with this display. + continue + } + + val boundsPx = + MultiDisplayDragMoveBoundsCalculator.convertGlobalDpToLocalPxForRect( + boundsDp, + displayLayout, + ) + + // Get or create the inner map for the current task. + val dragIndicatorsForTask = + dragIndicators.getOrPut(taskInfo.taskId) { mutableMapOf() } + dragIndicatorsForTask[displayId]?.also { existingIndicator -> + val transaction = transactionSupplier() + existingIndicator.relayout(boundsPx, transaction, shouldBeVisible) + transaction.apply() + } ?: run { + val newIndicator = + indicatorSurfaceFactory.create( + taskInfo, + displayController.getDisplay(displayId), + ) + newIndicator.show( + transactionSupplier(), + taskInfo, + rootTaskDisplayAreaOrganizer, + displayId, + boundsPx, + ) + dragIndicatorsForTask[displayId] = newIndicator + } + } + } + } + + /** + * Called when the drag ends. Disposes of the drag move indicator surfaces associated with the + * given [taskId]. [transactionSupplier] provides a [SurfaceControl.Transaction] for applying + * changes to the indicator surfaces. + * + * It is executed on the [desktopExecutor] to ensure that any pending `onDragMove` operations + * have completed before disposing of the surfaces. + */ + fun onDragEnd(taskId: Int, transactionSupplier: () -> SurfaceControl.Transaction) { + desktopExecutor.execute { + dragIndicators.remove(taskId)?.values?.takeIf { it.isNotEmpty() }?.let { indicators -> + val transaction = transactionSupplier() + indicators.forEach { indicator -> + indicator.disposeSurface(transaction) + } + transaction.apply() + } + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorSurface.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorSurface.kt new file mode 100644 index 000000000000..d05d3b0903d7 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorSurface.kt @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.common + +import android.app.ActivityManager.RunningTaskInfo +import android.content.Context +import android.graphics.Color +import android.graphics.Rect +import android.os.Trace +import android.view.Display +import android.view.SurfaceControl +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.ui.graphics.toArgb +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.windowdecor.common.DecorThemeUtil +import com.android.wm.shell.windowdecor.common.Theme + +/** + * Represents the indicator surface that visualizes the current position of a dragged window during + * a multi-display drag operation. + * + * This class manages the creation, display, and manipulation of the [SurfaceControl]s that act as a + * visual indicator, providing feedback to the user about the dragged window's location. + */ +class MultiDisplayDragMoveIndicatorSurface( + context: Context, + taskInfo: RunningTaskInfo, + display: Display, + surfaceControlBuilderFactory: Factory.SurfaceControlBuilderFactory, +) { + private var isVisible = false + + // A container surface to host the veil background + private var veilSurface: SurfaceControl? = null + + private val decorThemeUtil = DecorThemeUtil(context) + private val lightColors = dynamicLightColorScheme(context) + private val darkColors = dynamicDarkColorScheme(context) + + init { + Trace.beginSection("DragIndicatorSurface#init") + + val displayId = display.displayId + veilSurface = + surfaceControlBuilderFactory + .create("Drag indicator veil of Task=${taskInfo.taskId} Display=$displayId") + .setColorLayer() + .setCallsite("DragIndicatorSurface#init") + .setHidden(true) + .build() + + // TODO: b/383069173 - Add icon for the surface. + + Trace.endSection() + } + + /** + * Disposes the indicator surface using the provided [transaction]. + */ + fun disposeSurface(transaction: SurfaceControl.Transaction) { + veilSurface?.let { veil -> transaction.remove(veil) } + veilSurface = null + } + + /** + * Shows the indicator surface at [bounds] on the specified display ([displayId]), + * visualizing the drag of the [taskInfo]. The indicator surface is shown using [transaction], + * and the [rootTaskDisplayAreaOrganizer] is used to reparent the surfaces. + */ + fun show( + transaction: SurfaceControl.Transaction, + taskInfo: RunningTaskInfo, + rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, + displayId: Int, + bounds: Rect, + ) { + val backgroundColor = + when (decorThemeUtil.getAppTheme(taskInfo)) { + Theme.LIGHT -> lightColors.surfaceContainer + Theme.DARK -> darkColors.surfaceContainer + } + val veil = veilSurface ?: return + isVisible = true + + rootTaskDisplayAreaOrganizer.reparentToDisplayArea(displayId, veil, transaction) + relayout(bounds, transaction, shouldBeVisible = true) + transaction.show(veil).setColor(veil, Color.valueOf(backgroundColor.toArgb()).components) + transaction.apply() + } + + /** + * Repositions and resizes the indicator surface based on [bounds] using [transaction]. The + * [shouldBeVisible] flag indicates whether the indicator is within the display after relayout. + */ + fun relayout(bounds: Rect, transaction: SurfaceControl.Transaction, shouldBeVisible: Boolean) { + if (!isVisible && !shouldBeVisible) { + // No need to relayout if the surface is already invisible and should not be visible. + return + } + isVisible = shouldBeVisible + val veil = veilSurface ?: return + transaction.setCrop(veil, bounds) + } + + /** + * Factory for creating [MultiDisplayDragMoveIndicatorSurface] instances with the [context]. + */ + class Factory(private val context: Context) { + private val surfaceControlBuilderFactory: SurfaceControlBuilderFactory = + object : SurfaceControlBuilderFactory {} + + /** + * Creates a new [MultiDisplayDragMoveIndicatorSurface] instance to visualize the drag + * operation of the [taskInfo] on the given [display]. + */ + fun create( + taskInfo: RunningTaskInfo, + display: Display, + ) = MultiDisplayDragMoveIndicatorSurface( + context, + taskInfo, + display, + surfaceControlBuilderFactory, + ) + + /** + * Interface for creating [SurfaceControl.Builder] instances. + * + * This provides an abstraction over [SurfaceControl.Builder] creation for testing purposes. + */ + interface SurfaceControlBuilderFactory { + fun create(name: String): SurfaceControl.Builder { + return SurfaceControl.Builder().setName(name) + } + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OffscreenTouchZone.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OffscreenTouchZone.java index 381f0b037023..3211307c6f9b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OffscreenTouchZone.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/OffscreenTouchZone.java @@ -56,6 +56,7 @@ public class OffscreenTouchZone { /** The function that will be run when this zone is tapped. */ private final Runnable mOnClickRunnable; private SurfaceControlViewHost mViewHost; + private SurfaceControl mLeash; /** * @param isTopLeft Whether the desired touch zone will be on the top/left or the bottom/right @@ -96,6 +97,7 @@ public class OffscreenTouchZone { .setCallsite("OffscreenTouchZone::init"); builder.setParent(stageRoot); SurfaceControl leash = builder.build(); + mLeash = leash; // Create a ViewHost that will hold our view. WindowlessWindowManager wwm = new WindowlessWindowManager(config, leash, null); @@ -117,10 +119,14 @@ public class OffscreenTouchZone { } /** Releases the touch zone when it's no longer needed. */ - void release() { + void release(SurfaceControl.Transaction t) { if (mViewHost != null) { mViewHost.release(); } + if (mLeash != null) { + t.remove(mLeash); + mLeash = null; + } } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 708e26cc5546..720e8e53b218 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -461,7 +461,14 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange return; } - mOffscreenTouchZones.forEach(OffscreenTouchZone::release); + // TODO (b/349828130): It would be good to reuse a Transaction from StageCoordinator's + // mTransactionPool here, but passing it through SplitLayout and specifically + // SplitLayout.release() is complicated because that function is purposely called with a + // null value sometimes. When that function is refactored, we should also pass the + // Transaction in here. + SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + mOffscreenTouchZones.forEach(touchZone -> touchZone.release(t)); + t.apply(); mOffscreenTouchZones.clear(); } @@ -975,8 +982,16 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange final boolean shouldVeil = insets.left != 0 || insets.top != 0 || insets.right != 0 || insets.bottom != 0; + // Find the "left/top"-most position of the app surface -- usually 0, but sometimes negative + // if the left/top app is offscreen. + int leftTop = 0; + if (Flags.enableFlexibleTwoAppSplit()) { + leftTop = mIsLeftRightSplit ? getTopLeftBounds().left : getTopLeftBounds().top; + } + final int dividerPos = mDividerSnapAlgorithm.calculateNonDismissingSnapTarget( - mIsLeftRightSplit ? getBottomRightBounds().width() : getBottomRightBounds().height() + leftTop + (mIsLeftRightSplit + ? getBottomRightBounds().width() : getBottomRightBounds().height()) ).position; final Rect endBounds1 = new Rect(); final Rect endBounds2 = new Rect(); 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 2fd8c27d5970..5a246e7c99b9 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 @@ -68,6 +68,8 @@ import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.LaunchAdjacentController; +import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController; +import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorSurface; import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; @@ -82,6 +84,7 @@ import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler; import com.android.wm.shell.desktopmode.DefaultDragToDesktopTransitionHandler; import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler; import com.android.wm.shell.desktopmode.DesktopDisplayEventHandler; +import com.android.wm.shell.desktopmode.DesktopDisplayModeController; import com.android.wm.shell.desktopmode.DesktopImmersiveController; import com.android.wm.shell.desktopmode.DesktopMinimizationTransitionHandler; import com.android.wm.shell.desktopmode.DesktopMixedTransitionHandler; @@ -989,7 +992,8 @@ public abstract class WMShellModule { WindowDecorTaskResourceLoader taskResourceLoader, RecentsTransitionHandler recentsTransitionHandler, DesktopModeCompatPolicy desktopModeCompatPolicy, - DesktopTilingDecorViewModel desktopTilingDecorViewModel + DesktopTilingDecorViewModel desktopTilingDecorViewModel, + MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController ) { if (!DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)) { return Optional.empty(); @@ -1006,7 +1010,30 @@ public abstract class WMShellModule { windowDecorCaptionHandleRepository, activityOrientationChangeHandler, focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy, - desktopTilingDecorViewModel)); + desktopTilingDecorViewModel, + multiDisplayDragMoveIndicatorController)); + } + + @WMSingleton + @Provides + static MultiDisplayDragMoveIndicatorController + providesMultiDisplayDragMoveIndicatorController( + DisplayController displayController, + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + MultiDisplayDragMoveIndicatorSurface.Factory + multiDisplayDragMoveIndicatorSurfaceFactory, + @ShellDesktopThread ShellExecutor desktopExecutor + ) { + return new MultiDisplayDragMoveIndicatorController( + displayController, rootTaskDisplayAreaOrganizer, + multiDisplayDragMoveIndicatorSurfaceFactory, desktopExecutor); + } + + @WMSingleton + @Provides + static MultiDisplayDragMoveIndicatorSurface.Factory + providesMultiDisplayDragMoveIndicatorSurfaceFactory(Context context) { + return new MultiDisplayDragMoveIndicatorSurface.Factory(context); } @WMSingleton @@ -1230,13 +1257,10 @@ public abstract class WMShellModule { static Optional<DesktopDisplayEventHandler> provideDesktopDisplayEventHandler( Context context, ShellInit shellInit, - Transitions transitions, DisplayController displayController, - RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, - IWindowManager windowManager, Optional<DesktopUserRepositories> desktopUserRepositories, Optional<DesktopTasksController> desktopTasksController, - ShellTaskOrganizer shellTaskOrganizer + Optional<DesktopDisplayModeController> desktopDisplayModeController ) { if (!DesktopModeStatus.canEnterDesktopMode(context)) { return Optional.empty(); @@ -1245,13 +1269,10 @@ public abstract class WMShellModule { new DesktopDisplayEventHandler( context, shellInit, - transitions, displayController, - rootTaskDisplayAreaOrganizer, - windowManager, desktopUserRepositories.get(), desktopTasksController.get(), - shellTaskOrganizer)); + desktopDisplayModeController.get())); } @WMSingleton @@ -1381,6 +1402,29 @@ public abstract class WMShellModule { return new DesktopModeUiEventLogger(uiEventLogger, packageManager); } + @WMSingleton + @Provides + static Optional<DesktopDisplayModeController> provideDesktopDisplayModeController( + Context context, + Transitions transitions, + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + IWindowManager windowManager, + ShellTaskOrganizer shellTaskOrganizer, + DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider + ) { + if (!DesktopModeStatus.canEnterDesktopMode(context)) { + return Optional.empty(); + } + return Optional.of( + new DesktopDisplayModeController( + context, + transitions, + rootTaskDisplayAreaOrganizer, + windowManager, + shellTaskOrganizer, + desktopWallpaperActivityTokenProvider)); + } + // // App zoom out // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt index c38558d7bde9..946e7952dd50 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandler.kt @@ -16,41 +16,25 @@ package com.android.wm.shell.desktopmode -import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD -import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM -import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED -import android.app.WindowConfiguration.windowingModeToString import android.content.Context -import android.provider.Settings -import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS import android.view.Display.DEFAULT_DISPLAY -import android.view.IWindowManager -import android.view.WindowManager.TRANSIT_CHANGE import android.window.DesktopExperienceFlags -import android.window.WindowContainerTransaction import com.android.internal.protolog.ProtoLog -import com.android.window.flags.Flags -import com.android.wm.shell.RootTaskDisplayAreaOrganizer -import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener import com.android.wm.shell.desktopmode.multidesks.OnDeskRemovedListener import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit -import com.android.wm.shell.transition.Transitions /** Handles display events in desktop mode */ class DesktopDisplayEventHandler( private val context: Context, shellInit: ShellInit, - private val transitions: Transitions, private val displayController: DisplayController, - private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, - private val windowManager: IWindowManager, private val desktopUserRepositories: DesktopUserRepositories, private val desktopTasksController: DesktopTasksController, - private val shellTaskOrganizer: ShellTaskOrganizer, + private val desktopDisplayModeController: DesktopDisplayModeController, ) : OnDisplaysChangedListener, OnDeskRemovedListener { private val desktopRepository: DesktopRepository @@ -70,7 +54,7 @@ class DesktopDisplayEventHandler( override fun onDisplayAdded(displayId: Int) { if (displayId != DEFAULT_DISPLAY) { - refreshDisplayWindowingMode() + desktopDisplayModeController.refreshDisplayWindowingMode() } if (!supportsDesks(displayId)) { @@ -88,7 +72,7 @@ class DesktopDisplayEventHandler( override fun onDisplayRemoved(displayId: Int) { if (displayId != DEFAULT_DISPLAY) { - refreshDisplayWindowingMode() + desktopDisplayModeController.refreshDisplayWindowingMode() } // TODO: b/362720497 - move desks in closing display to the remaining desk. @@ -102,65 +86,6 @@ class DesktopDisplayEventHandler( } } - private fun refreshDisplayWindowingMode() { - if (!Flags.enableDisplayWindowingModeSwitching()) return - // TODO: b/375319538 - Replace the check with a DisplayManager API once it's available. - val isExtendedDisplayEnabled = - 0 != - Settings.Global.getInt( - context.contentResolver, - DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, - 0, - ) - if (!isExtendedDisplayEnabled) { - // No action needed in mirror or projected mode. - return - } - - val hasNonDefaultDisplay = - rootTaskDisplayAreaOrganizer.getDisplayIds().any { displayId -> - displayId != DEFAULT_DISPLAY - } - val targetDisplayWindowingMode = - if (hasNonDefaultDisplay) { - WINDOWING_MODE_FREEFORM - } else { - // Use the default display windowing mode when no non-default display. - windowManager.getWindowingMode(DEFAULT_DISPLAY) - } - val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY) - requireNotNull(tdaInfo) { "DisplayAreaInfo of DEFAULT_DISPLAY must be non-null." } - val currentDisplayWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode - if (currentDisplayWindowingMode == targetDisplayWindowingMode) { - // Already in the target mode. - return - } - - logV( - "As an external display is connected, changing default display's windowing mode from" + - " ${windowingModeToString(currentDisplayWindowingMode)}" + - " to ${windowingModeToString(targetDisplayWindowingMode)}" - ) - - val wct = WindowContainerTransaction() - wct.setWindowingMode(tdaInfo.token, targetDisplayWindowingMode) - shellTaskOrganizer - .getRunningTasks(DEFAULT_DISPLAY) - .filter { it.activityType == ACTIVITY_TYPE_STANDARD } - .forEach { - // TODO: b/391965153 - Reconsider the logic under multi-desk window hierarchy - when (it.windowingMode) { - currentDisplayWindowingMode -> { - wct.setWindowingMode(it.token, currentDisplayWindowingMode) - } - targetDisplayWindowingMode -> { - wct.setWindowingMode(it.token, WINDOWING_MODE_UNDEFINED) - } - } - } - transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) - } - // TODO: b/362720497 - connected/projected display considerations. private fun supportsDesks(displayId: Int): Boolean = DesktopModeStatus.canEnterDesktopMode(context) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt new file mode 100644 index 000000000000..c9a63ff818f5 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopDisplayModeController.kt @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.desktopmode + +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED +import android.app.WindowConfiguration.windowingModeToString +import android.content.Context +import android.provider.Settings +import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS +import android.view.Display.DEFAULT_DISPLAY +import android.view.IWindowManager +import android.view.WindowManager.TRANSIT_CHANGE +import android.window.WindowContainerTransaction +import com.android.internal.protolog.ProtoLog +import com.android.window.flags.Flags +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import com.android.wm.shell.transition.Transitions + +/** Controls the display windowing mode in desktop mode */ +class DesktopDisplayModeController( + private val context: Context, + private val transitions: Transitions, + private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, + private val windowManager: IWindowManager, + private val shellTaskOrganizer: ShellTaskOrganizer, + private val desktopWallpaperActivityTokenProvider: DesktopWallpaperActivityTokenProvider, +) { + + fun refreshDisplayWindowingMode() { + if (!Flags.enableDisplayWindowingModeSwitching()) return + // TODO: b/375319538 - Replace the check with a DisplayManager API once it's available. + val isExtendedDisplayEnabled = + 0 != + Settings.Global.getInt( + context.contentResolver, + DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, + 0, + ) + if (!isExtendedDisplayEnabled) { + // No action needed in mirror or projected mode. + return + } + + val hasNonDefaultDisplay = + rootTaskDisplayAreaOrganizer.getDisplayIds().any { displayId -> + displayId != DEFAULT_DISPLAY + } + val targetDisplayWindowingMode = + if (hasNonDefaultDisplay) { + WINDOWING_MODE_FREEFORM + } else { + // Use the default display windowing mode when no non-default display. + windowManager.getWindowingMode(DEFAULT_DISPLAY) + } + val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY) + requireNotNull(tdaInfo) { "DisplayAreaInfo of DEFAULT_DISPLAY must be non-null." } + val currentDisplayWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode + if (currentDisplayWindowingMode == targetDisplayWindowingMode) { + // Already in the target mode. + return + } + + logV( + "As an external display is connected, changing default display's windowing mode from" + + " ${windowingModeToString(currentDisplayWindowingMode)}" + + " to ${windowingModeToString(targetDisplayWindowingMode)}" + ) + + val wct = WindowContainerTransaction() + wct.setWindowingMode(tdaInfo.token, targetDisplayWindowingMode) + shellTaskOrganizer + .getRunningTasks(DEFAULT_DISPLAY) + .filter { it.activityType == ACTIVITY_TYPE_STANDARD } + .forEach { + // TODO: b/391965153 - Reconsider the logic under multi-desk window hierarchy + when (it.windowingMode) { + currentDisplayWindowingMode -> { + wct.setWindowingMode(it.token, currentDisplayWindowingMode) + } + targetDisplayWindowingMode -> { + wct.setWindowingMode(it.token, WINDOWING_MODE_UNDEFINED) + } + } + } + // The override windowing mode of DesktopWallpaper can be UNDEFINED on fullscreen-display + // right after the first launch while its resolved windowing mode is FULLSCREEN. We here + // it has the FULLSCREEN override windowing mode. + desktopWallpaperActivityTokenProvider.getToken(DEFAULT_DISPLAY)?.let { token -> + wct.setWindowingMode(token, WINDOWING_MODE_FULLSCREEN) + } + transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null) + } + + private fun logV(msg: String, vararg arguments: Any?) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + companion object { + private const val TAG = "DesktopDisplayModeController" + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt index 9b850de6fede..c5ee3137e5ba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt @@ -33,6 +33,7 @@ import android.util.Size import com.android.wm.shell.R import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout +import kotlin.math.ceil val DESKTOP_MODE_INITIAL_BOUNDS_SCALE: Float = SystemProperties.getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f @@ -190,22 +191,22 @@ fun maximizeSizeGivenAspectRatio( val finalWidth: Int // Get orientation either through top activity or task's orientation if (taskInfo.hasPortraitTopActivity()) { - val tempWidth = (targetHeight / aspectRatio).toInt() + val tempWidth = ceil(targetHeight / aspectRatio).toInt() if (tempWidth <= targetWidth) { finalHeight = targetHeight finalWidth = tempWidth } else { finalWidth = targetWidth - finalHeight = (finalWidth * aspectRatio).toInt() + finalHeight = ceil(finalWidth * aspectRatio).toInt() } } else { - val tempWidth = (targetHeight * aspectRatio).toInt() + val tempWidth = ceil(targetHeight * aspectRatio).toInt() if (tempWidth <= targetWidth) { finalHeight = targetHeight finalWidth = tempWidth } else { finalWidth = targetWidth - finalHeight = (finalWidth / aspectRatio).toInt() + finalHeight = ceil(finalWidth / aspectRatio).toInt() } } return Size(finalWidth, finalHeight + captionInsets) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt index eba1be517147..c60fc1646c32 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt @@ -208,6 +208,7 @@ class DesktopRepository( /** Adds the given desk under the given display. */ fun addDesk(displayId: Int, deskId: Int) { + logD("addDesk for displayId=%d and deskId=%d", displayId, deskId) desktopData.createDesk(displayId, deskId) } @@ -224,6 +225,7 @@ class DesktopRepository( /** Sets the given desk as the active one in the given display. */ fun setActiveDesk(displayId: Int, deskId: Int) { + logD("setActiveDesk for displayId=%d and deskId=%d", displayId, deskId) desktopData.setActiveDesk(displayId = displayId, deskId = deskId) } @@ -246,6 +248,7 @@ class DesktopRepository( * TODO: b/389960283 - add explicit [deskId] argument. */ fun addTask(displayId: Int, taskId: Int, isVisible: Boolean) { + logD("addTask for displayId=%d, taskId=%d, isVisible=%b", displayId, taskId, isVisible) val activeDesk = checkNotNull(desktopData.getDefaultDesk(displayId)) { "Expected desk in display: $displayId" @@ -254,6 +257,13 @@ class DesktopRepository( } fun addTaskToDesk(displayId: Int, deskId: Int, taskId: Int, isVisible: Boolean) { + logD( + "addTaskToDesk for displayId=%d, deskId=%d, taskId=%d, isVisible=%b", + displayId, + deskId, + taskId, + isVisible, + ) addOrMoveTaskToTopOfDesk(displayId = displayId, deskId = deskId, taskId = taskId) addActiveTaskToDesk(displayId = displayId, deskId = deskId, taskId = taskId) updateTaskInDesk( @@ -265,6 +275,12 @@ class DesktopRepository( } private fun addActiveTaskToDesk(displayId: Int, deskId: Int, taskId: Int) { + logD( + "addActiveTaskToDesk for displayId=%d, deskId=%d, taskId=%d", + displayId, + deskId, + taskId, + ) val desk = checkNotNull(desktopData.getDesk(deskId)) { "Did not find desk: $deskId" } // Removes task if it is active on another desk excluding this desk. @@ -279,6 +295,7 @@ class DesktopRepository( /** Removes task from active task list of desks excluding the [excludedDeskId]. */ @VisibleForTesting fun removeActiveTask(taskId: Int, excludedDeskId: Int? = null) { + logD("removeActiveTask for taskId=%d, excludedDeskId=%d", taskId, excludedDeskId) val affectedDisplays = mutableSetOf<Int>() desktopData .desksSequence() @@ -303,6 +320,7 @@ class DesktopRepository( taskId: Int, notifyListeners: Boolean = true, ): Boolean { + logD("removeActiveTaskFromDesk for deskId=%d, taskId=%d", deskId, taskId) val desk = desktopData.getDesk(deskId) ?: return false if (desk.activeTasks.remove(taskId)) { logD("Removed active task=%d from deskId=%d", taskId, desk.deskId) @@ -456,7 +474,7 @@ class DesktopRepository( /** Removes task from visible tasks of all desks except [excludedDeskId]. */ private fun removeVisibleTask(taskId: Int, excludedDeskId: Int? = null) { - desktopData.forAllDesks { displayId, desk -> + desktopData.forAllDesks { _, desk -> if (desk.deskId != excludedDeskId) { removeVisibleTaskFromDesk(deskId = desk.deskId, taskId = taskId) } @@ -668,6 +686,11 @@ class DesktopRepository( * TODO: b/389960283 - add explicit [deskId] argument. */ fun setTopTransparentFullscreenTaskId(displayId: Int, taskId: Int) { + logD( + "Top transparent fullscreen task set for display: taskId=%d, displayId=%d", + taskId, + displayId, + ) desktopData.getActiveDesk(displayId)?.topTransparentFullscreenTaskId = taskId } @@ -685,6 +708,11 @@ class DesktopRepository( * TODO: b/389960283 - add explicit [deskId] argument. */ fun clearTopTransparentFullscreenTaskId(displayId: Int) { + logD( + "Top transparent fullscreen task cleared for display: taskId=%d, displayId=%d", + desktopData.getActiveDesk(displayId)?.topTransparentFullscreenTaskId, + displayId, + ) desktopData.getActiveDesk(displayId)?.topTransparentFullscreenTaskId = null } @@ -718,6 +746,12 @@ class DesktopRepository( * Unminimizes the task if it is minimized. */ private fun addOrMoveTaskToTopOfDesk(displayId: Int, deskId: Int, taskId: Int) { + logD( + "addOrMoveTaskToTopOfDesk displayId=%d, deskId=%d, taskId=%d", + displayId, + deskId, + taskId, + ) val desk = desktopData.getDesk(deskId) ?: error("Could not find desk: $deskId") logD("addOrMoveTaskToTopOfDesk: display=%d deskId=%d taskId=%d", displayId, deskId, taskId) desktopData.forAllDesks { _, desk1 -> desk1.freeformTasksInZOrder.remove(taskId) } @@ -738,6 +772,7 @@ class DesktopRepository( * desk id instead of using this function and defaulting to the active one. */ fun minimizeTask(displayId: Int, taskId: Int) { + logD("minimizeTask displayId=%d, taskId=%d", displayId, taskId) if (displayId == INVALID_DISPLAY) { // When a task vanishes it doesn't have a displayId. Find the display of the task and // mark it as minimized. @@ -756,7 +791,7 @@ class DesktopRepository( /** Minimizes the task in its desk. */ @VisibleForTesting fun minimizeTaskInDesk(displayId: Int, deskId: Int, taskId: Int) { - logD("Minimize Task: displayId=%d deskId=%d, task=%d", displayId, deskId, taskId) + logD("MinimizeTaskInDesk: displayId=%d deskId=%d, task=%d", displayId, deskId, taskId) desktopData.getDesk(deskId)?.minimizedTasks?.add(taskId) ?: logD("Minimize task: No active desk found for task: taskId=%d", taskId) updateTaskInDesk(displayId, deskId, taskId, isVisible = false) @@ -771,12 +806,12 @@ class DesktopRepository( * TODO: b/389960283 - consider using [unminimizeTaskFromDesk] instead. */ fun unminimizeTask(displayId: Int, taskId: Int) { - logD("Unminimize Task: display=%d, task=%d", displayId, taskId) + logD("UnminimizeTask: display=%d, task=%d", displayId, taskId) desktopData.forAllDesks(displayId) { desk -> unminimizeTaskFromDesk(desk.deskId, taskId) } } private fun unminimizeTaskFromDesk(deskId: Int, taskId: Int) { - logD("Unminimize Task: deskId=%d, taskId=%d", deskId, taskId) + logD("Unminimize Task from desk: deskId=%d, taskId=%d", deskId, taskId) if (desktopData.getDesk(deskId)?.minimizedTasks?.remove(taskId) != true) { logW("Unminimize Task: deskId=%d, taskId=%d, no task data", deskId, taskId) } @@ -847,6 +882,7 @@ class DesktopRepository( /** Removes the given desk and returns the active tasks in that desk. */ fun removeDesk(deskId: Int): Set<Int> { + logD("removeDesk %d", deskId) val desk = desktopData.getDesk(deskId) ?: return emptySet<Int>().also { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt index e831d5eecdc2..6034299453fb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt @@ -19,13 +19,16 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.window.DesktopModeFlags +import com.android.internal.protolog.ProtoLog import com.android.wm.shell.freeform.TaskChangeListener +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE /** Manages tasks handling specific to Android Desktop Mode. */ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUserRepositories) : TaskChangeListener { override fun onTaskOpening(taskInfo: RunningTaskInfo) { + logD("onTaskOpening for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) { @@ -38,6 +41,7 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser } override fun onTaskChanging(taskInfo: RunningTaskInfo) { + logD("onTaskChanging for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return @@ -67,9 +71,15 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser // of race conditions and possible duplications with [onTaskChanging]. override fun onNonTransitionTaskChanging(taskInfo: RunningTaskInfo) { // TODO: b/367268953 - Propagate usages from FreeformTaskListener to this method. + logD( + "onNonTransitionTaskChanging for taskId=%d, displayId=%d", + taskInfo.taskId, + taskInfo.displayId, + ) } override fun onTaskMovingToFront(taskInfo: RunningTaskInfo) { + logD("onTaskMovingToFront for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return @@ -80,10 +90,12 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser } override fun onTaskMovingToBack(taskInfo: RunningTaskInfo) { + logD("onTaskMovingToBack for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) // TODO: b/367268953 - Connect this with DesktopRepository. } override fun onTaskClosing(taskInfo: RunningTaskInfo) { + logD("onTaskClosing for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return @@ -104,4 +116,12 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser private fun isFreeformTask(taskInfo: RunningTaskInfo): Boolean = taskInfo.windowingMode == WINDOWING_MODE_FREEFORM + + private fun logD(msg: String, vararg arguments: Any?) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + companion object { + private const val TAG = "DesktopTaskChangeListener" + } } 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 0afceac8a861..93058db0c171 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 @@ -73,6 +73,7 @@ import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELE import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog +import com.android.internal.util.LatencyTracker import com.android.window.flags.Flags import com.android.wm.shell.Flags.enableFlexibleSplit import com.android.wm.shell.R @@ -467,10 +468,7 @@ class DesktopTasksController( } // TODO(342378842): Instead of using default display, support multiple displays val displayId = runningTask?.displayId ?: DEFAULT_DISPLAY - val deskId = - checkNotNull(taskRepository.getDefaultDeskId(displayId)) { - "Expected a default desk to exist" - } + val deskId = getDefaultDeskId(displayId) return moveTaskToDesk( taskId = taskId, deskId = deskId, @@ -715,10 +713,7 @@ class DesktopTasksController( * [startDragToDesktop]. */ private fun finalizeDragToDesktop(taskInfo: RunningTaskInfo) { - val deskId = - checkNotNull(taskRepository.getDefaultDeskId(taskInfo.displayId)) { - "Expected a default desk to exist" - } + val deskId = getDefaultDeskId(taskInfo.displayId) ProtoLog.v( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: finalizeDragToDesktop taskId=%d deskId=%d", @@ -754,9 +749,9 @@ class DesktopTasksController( desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted( DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS.toInt() ) - transition?.let { - taskIdToMinimize?.let { taskId -> - addPendingMinimizeTransition(it, taskId, MinimizeReason.TASK_LIMIT) + if (transition != null) { + taskIdToMinimize?.let { + addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT) } exitResult.asExit()?.runOnTransitionStart?.invoke(transition) if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) { @@ -771,6 +766,9 @@ class DesktopTasksController( } else { taskRepository.setActiveDesk(displayId = taskInfo.displayId, deskId = deskId) } + } else { + LatencyTracker.getInstance(context) + .onActionCancel(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG) } } @@ -2050,8 +2048,10 @@ class DesktopTasksController( unminimizeReason = UnminimizeReason.APP_HANDLE_MENU_BUTTON, ) } else { - moveBackgroundTaskToDesktop( + val deskId = getDefaultDeskId(callingTask.displayId) + moveTaskToDesk( requestedTaskId, + deskId, WindowContainerTransaction(), DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON, ) @@ -2661,10 +2661,7 @@ class DesktopTasksController( displayId: Int, remoteTransition: RemoteTransition? = null, ) { - val deskId = - checkNotNull(taskRepository.getDefaultDeskId(displayId)) { - "Expected a default desk to exist" - } + val deskId = getDefaultDeskId(displayId) activateDesk(deskId, remoteTransition) } @@ -2728,13 +2725,15 @@ class DesktopTasksController( /** Removes the default desk in the given display. */ @Deprecated("Deprecated with multi-desks.", ReplaceWith("removeDesk()")) fun removeDefaultDeskInDisplay(displayId: Int) { - val deskId = - checkNotNull(taskRepository.getDefaultDeskId(displayId)) { - "Expected a default desk to exist" - } + val deskId = getDefaultDeskId(displayId) removeDesk(displayId = displayId, deskId = deskId) } + private fun getDefaultDeskId(displayId: Int) = + checkNotNull(taskRepository.getDefaultDeskId(displayId)) { + "Expected a default desk to exist in display: $displayId" + } + /** Removes the given desk. */ fun removeDesk(deskId: Int) { val displayId = taskRepository.getDisplayForDesk(deskId) @@ -3089,6 +3088,8 @@ class DesktopTasksController( val indicatorType = indicator.updateIndicatorType(inputCoordinates) when (indicatorType) { IndicatorType.TO_DESKTOP_INDICATOR -> { + LatencyTracker.getInstance(context) + .onActionStart(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG) // Start a new jank interaction for the drag release to desktop window animation. interactionJankMonitor.begin( taskSurface, @@ -3447,11 +3448,15 @@ class DesktopTasksController( } override fun createDesk(displayId: Int) { - // TODO: b/362720497 - Implement this API. + executeRemoteCallWithTaskPermission(controller, "createDesk") { c -> + c.createDesk(displayId) + } } override fun activateDesk(deskId: Int, remoteTransition: RemoteTransition?) { - // TODO: b/362720497 - Implement this API. + executeRemoteCallWithTaskPermission(controller, "activateDesk") { c -> + c.activateDesk(deskId, remoteTransition) + } } override fun showDesktopApps(displayId: Int, remoteTransition: RemoteTransition?) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt index 3ada988ba2a3..9a97ae8d61a0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt @@ -186,14 +186,16 @@ class DesktopTasksTransitionObserver( for (change in info.changes) { val taskInfo = change.taskInfo if (taskInfo == null || taskInfo.taskId == -1) continue - if (change.mode != TRANSIT_CLOSE) continue - if (minimizingTask == null) { - minimizingTask = getMinimizingTaskForClosingTransition(taskInfo) + if ( + TransitionUtil.isClosingMode(change.mode) && + DesktopWallpaperActivity.isWallpaperTask(taskInfo) + ) { + hasWallpaperClosing = true } - if (DesktopWallpaperActivity.isWallpaperTask(taskInfo)) { - hasWallpaperClosing = true + if (change.mode == TRANSIT_CLOSE && minimizingTask == null) { + minimizingTask = getMinimizingTaskForClosingTransition(taskInfo) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DisplayDeskState.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DisplayDeskState.aidl index 59add47fc79d..5f45192569e3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DisplayDeskState.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DisplayDeskState.aidl @@ -18,13 +18,11 @@ package com.android.wm.shell.desktopmode; /** * Defines the state of desks on a display whose ID is `displayId`, which is: - * - `canCreateDesks`: whether it's possible to create new desks on this display. * - `activeDeskId`: the currently active desk Id, or `-1` if none is active. * - `deskId`: the list of desk Ids of the available desks on this display. */ parcelable DisplayDeskState { int displayId; - boolean canCreateDesk; int activeDeskId; int[] deskIds; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt index 0929ae15e668..cb231800bd63 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt @@ -35,6 +35,7 @@ import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE import com.android.internal.jank.InteractionJankMonitor import com.android.internal.protolog.ProtoLog +import com.android.internal.util.LatencyTracker import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.FloatProperties import com.android.wm.shell.bubbles.BubbleController @@ -42,7 +43,7 @@ import com.android.wm.shell.bubbles.BubbleTransitions import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_CANCEL_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_END_DRAG_TO_DESKTOP import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP -import com.android.wm.shell.protolog.ShellProtoLogGroup +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.TransitionUtil import com.android.wm.shell.shared.animation.PhysicsAnimator import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT @@ -119,10 +120,7 @@ sealed class DragToDesktopTransitionHandler( dragToDesktopAnimator: MoveToDesktopAnimator, ) { if (inProgress) { - ProtoLog.v( - ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "DragToDesktop: Drag to desktop transition already in progress.", - ) + logV("Drag to desktop transition already in progress.") return } @@ -536,12 +534,14 @@ sealed class DragToDesktopTransitionHandler( state.cancelState == CancelState.CANCEL_SPLIT_LEFT || state.cancelState == CancelState.CANCEL_SPLIT_RIGHT ) { + logV("mergeAnimation: cancel through split") clearState() return } // In case of bubble animation, finish the initial desktop drag animation, but keep the // current animation running and have bubbles take over if (info.type == TRANSIT_CONVERT_TO_BUBBLE) { + logV("mergeAnimation: convert-to-bubble") state.startTransitionFinishCb?.onTransitionFinished(/* wct= */ null) clearState() return @@ -561,6 +561,7 @@ sealed class DragToDesktopTransitionHandler( state.startTransitionFinishCb ?: error("Start transition expected to be waiting for merge but wasn't") if (isEndTransition) { + logV("mergeAnimation: end-transition, target=$mergeTarget") setupEndDragToDesktop( info, startTransaction = startT, @@ -568,8 +569,15 @@ sealed class DragToDesktopTransitionHandler( ) // Call finishCallback to merge animation before startTransitionFinishCb is called finishCallback.onTransitionFinished(/* wct= */ null) + LatencyTracker.getInstance(context) + .onActionEnd(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG) animateEndDragToDesktop(startTransaction = startT, startTransitionFinishCb) - } else if (isCancelTransition) { + return + } + if (isCancelTransition) { + logV("mergeAnimation: cancel-transition, target=$mergeTarget") + LatencyTracker.getInstance(context) + .onActionCancel(LatencyTracker.ACTION_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG) info.changes.forEach { change -> startT.show(change.leash) startTransactionFinishT.show(change.leash) @@ -578,7 +586,9 @@ sealed class DragToDesktopTransitionHandler( finishCallback.onTransitionFinished(/* wct= */ null) startTransitionFinishCb.onTransitionFinished(/* wct= */ null) clearState() + return } + logW("unhandled merge transition: transitionInfo=$info") } protected open fun setupEndDragToDesktop( @@ -719,10 +729,7 @@ sealed class DragToDesktopTransitionHandler( return } if (state.startTransitionToken == transition) { - ProtoLog.v( - ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "DragToDesktop: onTransitionConsumed() start transition aborted", - ) + logV("onTransitionConsumed() start transition aborted") state.startAborted = true // The start-transition (DRAG_HOLD) is aborted, cancel its jank interaction. interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD) @@ -945,7 +952,16 @@ sealed class DragToDesktopTransitionHandler( CANCEL_BUBBLE_RIGHT, } + private fun logV(msg: String, vararg arguments: Any?) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + private fun logW(msg: String, vararg arguments: Any?) { + ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + companion object { + private const val TAG = "DragToDesktopTransitionHandler" /** The duration of the animation to commit or cancel the drag-to-desktop gesture. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) const val DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS = 336L @@ -1047,10 +1063,7 @@ constructor( val state = requireTransitionState() val homeLeash = state.homeChange?.leash if (homeLeash == null) { - ProtoLog.e( - ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "DragToDesktop: home leash is null", - ) + logE("home leash is null") } else { // Hide home on finish to prevent flickering when wallpaper activity flag is enabled finishTransaction.hide(homeLeash) @@ -1091,6 +1104,12 @@ constructor( val startBoundsWithOffset = Rect(startBounds).apply { offset(startPosition.x.toInt(), startPosition.y.toInt()) } + logV( + "animateEndDragToDesktop: startBounds=$startBounds, endBounds=$endBounds, " + + "startScale=$startScale, startPosition=$startPosition, " + + "startBoundsWithOffset=$startBoundsWithOffset" + ) + dragToDesktopStateListener?.onCommitToDesktopAnimationStart() // Accept the merge by applying the merging transaction (applied by #showResizeVeil) // and finish callback. Show the veil and position the task at the first frame before @@ -1172,7 +1191,16 @@ constructor( .start() } + private fun logV(msg: String, vararg arguments: Any?) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + private fun logE(msg: String, vararg arguments: Any?) { + ProtoLog.e(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + companion object { + private const val TAG = "SpringDragToDesktopTransitionHandler" /** The freeform tasks initial scale when committing the drag-to-desktop gesture. */ private val FREEFORM_TASKS_INITIAL_SCALE = propertyValue("freeform_tasks_initial_scale", scale = 100f, default = 0.9f) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl index 7ed1581cdfdb..cefbd8947feb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopTaskListener.aidl @@ -28,7 +28,7 @@ oneway interface IDesktopTaskListener { * Called once when the listener first gets connected to initialize it with the current state of * desks in Shell. */ - void onListenerConnected(in DisplayDeskState[] displayDeskStates); + void onListenerConnected(in DisplayDeskState[] displayDeskStates, boolean canCreateDesks); /** Desktop tasks visibility has changed. Visible if at least 1 task is visible. */ void onTasksVisibilityChanged(int displayId, int visibleTasksCount); @@ -49,10 +49,10 @@ oneway interface IDesktopTaskListener { void onExitDesktopModeTransitionStarted(int transitionDuration); /** - * Called when the conditions that allow the creation of a new desk on the display whose ID is - * `displayId` changes to `canCreateDesks`. It's also called when a new display is added. + * Called when the conditions that allow the creation of a new desk changes. This is a global + * state for the entire device. */ - void onCanCreateDesksChanged(int displayId, boolean canCreateDesks); + void onCanCreateDesksChanged(boolean canCreateDesks); /** Called when a desk whose ID is `deskId` is added to the display whose ID is `displayId`. */ void onDeskAdded(int displayId, int deskId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt index 2a8a3475c2a5..b5490cb4b595 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt @@ -20,7 +20,7 @@ import android.util.SparseArray import android.util.SparseBooleanArray import android.view.Display.DEFAULT_DISPLAY import android.window.WindowContainerToken -import androidx.core.util.forEach +import androidx.core.util.keyIterator import com.android.internal.protolog.ProtoLog import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE @@ -45,11 +45,13 @@ class DesktopWallpaperActivityTokenProvider { } fun removeToken(token: WindowContainerToken) { - wallpaperActivityTokenByDisplayId.forEach { displayId, value -> - if (value == token) { - logV("Remove desktop wallpaper activity token for display %s", displayId) - wallpaperActivityTokenByDisplayId.delete(displayId) + val displayId = + wallpaperActivityTokenByDisplayId.keyIterator().asSequence().find { + wallpaperActivityTokenByDisplayId[it] == token } + if (displayId != null) { + logV("Remove desktop wallpaper activity token for display %s", displayId) + wallpaperActivityTokenByDisplayId.delete(displayId) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java index 118ad9c4bfe3..fa14bc91c8ab 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipAccessibilityInteractionConnection.java @@ -30,6 +30,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; +import android.view.accessibility.IWindowSurfaceInfoCallback; import android.window.ScreenCapture; import androidx.annotation.BinderThread; @@ -373,6 +374,13 @@ public class PipAccessibilityInteractionConnection { } @Override + public void getWindowSurfaceInfo(IWindowSurfaceInfoCallback callback) { + // AbstractAccessibilityServiceConnection uses the standard + // IAccessibilityInteractionConnection for takeScreenshotOfWindow for Pip windows, + // so do nothing here. + } + + @Override public void clearAccessibilityFocus() throws RemoteException { // Do nothing } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java index 71697596afd3..a837e7d308eb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipDismissTargetHandler.java @@ -296,6 +296,7 @@ public class PipDismissTargetHandler implements ViewTreeObserver.OnPreDrawListen return; } + mMagneticTarget.updateLocationOnScreen(); createOrUpdateDismissTarget(); if (mTargetViewContainer.getVisibility() != View.VISIBLE) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index e7bffe3bc4bc..035c93db7ee4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -728,7 +728,8 @@ public class PipTransition extends PipTransitionController implements // If PiP is enabled on Connected Displays, update PipDisplayLayoutState to have the correct // display info that PiP is entering in. - if (mPipDesktopState.isConnectedDisplaysPipEnabled()) { + if (mPipDesktopState.isConnectedDisplaysPipEnabled() + && pipTask.displayId != mPipDisplayLayoutState.getDisplayId()) { final DisplayLayout displayLayout = mDisplayController.getDisplayLayout( pipTask.displayId); if (displayLayout != null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index 4f2e028a1df0..2fa09664b73f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -381,7 +381,8 @@ public class RecentTasksController implements TaskStackListenerCallback, private void notifyRunningTaskAppeared(RunningTaskInfo taskInfo) { if (mListener == null || !shouldEnableRunningTasksForDesktopMode() - || taskInfo.realActivity == null) { + || taskInfo.realActivity == null + || excludeTaskFromGeneratedList(taskInfo)) { return; } try { @@ -397,7 +398,8 @@ public class RecentTasksController implements TaskStackListenerCallback, private void notifyRunningTaskChanged(RunningTaskInfo taskInfo) { if (mListener == null || !shouldEnableRunningTasksForDesktopMode() - || taskInfo.realActivity == null) { + || taskInfo.realActivity == null + || excludeTaskFromGeneratedList(taskInfo)) { return; } try { @@ -413,7 +415,8 @@ public class RecentTasksController implements TaskStackListenerCallback, private void notifyRunningTaskVanished(RunningTaskInfo taskInfo) { if (mListener == null || !shouldEnableRunningTasksForDesktopMode() - || taskInfo.realActivity == null) { + || taskInfo.realActivity == null + || excludeTaskFromGeneratedList(taskInfo)) { return; } try { @@ -430,7 +433,8 @@ public class RecentTasksController implements TaskStackListenerCallback, if (mListener == null || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue() || taskInfo.realActivity == null - || enableShellTopTaskTracking()) { + || enableShellTopTaskTracking() + || excludeTaskFromGeneratedList(taskInfo)) { return; } try { @@ -447,7 +451,8 @@ public class RecentTasksController implements TaskStackListenerCallback, if (mListener == null || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue() || taskInfo.realActivity == null - || enableShellTopTaskTracking()) { + || enableShellTopTaskTracking() + || excludeTaskFromGeneratedList(taskInfo)) { return; } try { 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 73b42d6f007c..77a7c5406a67 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 @@ -1317,6 +1317,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, WindowContainerTransaction noFocus = new WindowContainerTransaction(); noFocus.setFocusable(mRootTaskInfo.token, false); mSyncQueue.queue(noFocus); + // Remove touch layers, since offscreen apps coming onscreen will not need their touch + // layers anymore. populateTouchZones() is called in the end callback to inflate new touch + // layers in the appropriate places. + mSplitLayout.removeTouchZones(); mSplitLayout.playSwapAnimation(t, topLeftStage, bottomRightStage, insets -> { @@ -1337,6 +1341,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSyncQueue.runInSync(st -> { mSplitLayout.updateStateWithCurrentPosition(); updateSurfaceBounds(mSplitLayout, st, false /* applyResizingOffset */); + mSplitLayout.populateTouchZones(); // updateSurfaceBounds(), above, officially puts the two apps in their new // stages. Starting on the next frame, all calculations are made using the diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index c5994f83429a..e132c5ee7c6b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -681,7 +681,8 @@ public class SplashscreenContentDrawer { // C. The background of the adaptive icon is grayscale, and the foreground of the // adaptive icon forms a certain contrast with the theme color. // D. Didn't specify icon background color. - if (!iconColor.mIsBgComplex && mTmpAttrs.mIconBgColor == Color.TRANSPARENT + if (iconForeground != null + && !iconColor.mIsBgComplex && mTmpAttrs.mIconBgColor == Color.TRANSPARENT && (isRgbSimilarInHsv(mThemeColor, iconColor.mBgColor) || (iconColor.mIsBgGrayscale && !isRgbSimilarInHsv(mThemeColor, iconColor.mFgColor)))) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java index cc962acf1182..caed194c5fd8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java @@ -368,8 +368,12 @@ class SplashscreenWindowCreator extends AbsSplashWindowCreator { mStartingWindowRecordManager.addRecord(taskId, tView); } - private void removeWindowInner(@NonNull View decorView, boolean hideView) { + private void removeWindowInner(@NonNull View decorView, StartingWindowRemovalInfo info, + boolean hideView) { requestTopUi(false); + if (info.windowAnimationLeash != null && info.windowAnimationLeash.isValid()) { + info.windowAnimationLeash.release(); + } if (decorView.getParent() == null) { Slog.w(TAG, "This root view has no parent, never been added to a ViewRootImpl?"); return; @@ -452,22 +456,22 @@ class SplashscreenWindowCreator extends AbsSplashWindowCreator { if (mSplashView == null) { // shouldn't happen, the app window may be drawn earlier than starting window? Slog.e(TAG, "Found empty splash screen, remove!"); - removeWindowInner(mRootView, false); + removeWindowInner(mRootView, info, false); return true; } if (immediately || mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) { - removeWindowInner(mRootView, false); + removeWindowInner(mRootView, info, false); } else { if (info.playRevealAnimation) { mSplashscreenContentDrawer.applyExitAnimation(mSplashView, info.windowAnimationLeash, info.mainFrame, - () -> removeWindowInner(mRootView, true), + () -> removeWindowInner(mRootView, info, true), mCreateTime, info.roundedCornerRadius); } else { // the SplashScreenView has been copied to client, hide the view to skip // default exit animation - removeWindowInner(mRootView, true); + removeWindowInner(mRootView, info, true); } } return true; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java index dd5439a8aa10..7871179a50de 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java @@ -339,6 +339,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT taskInfo, taskSurface, mMainHandler, + mMainExecutor, mBgExecutor, mMainChoreographer, mSyncQueue, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java index 23bb2aa616f9..49510c8060fc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java @@ -48,6 +48,8 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.WindowInsets; import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.window.DesktopModeFlags; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; @@ -58,6 +60,7 @@ import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; +import com.android.wm.shell.shared.annotations.ShellMainThread; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; import com.android.wm.shell.windowdecor.extension.TaskInfoKt; @@ -69,6 +72,7 @@ import com.android.wm.shell.windowdecor.extension.TaskInfoKt; */ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> { private final Handler mHandler; + private final @ShellMainThread ShellExecutor mMainExecutor; private final @ShellBackgroundThread ShellExecutor mBgExecutor; private final Choreographer mChoreographer; private final SyncTransactionQueue mSyncQueue; @@ -90,6 +94,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL RunningTaskInfo taskInfo, SurfaceControl taskSurface, Handler handler, + @ShellMainThread ShellExecutor mainExecutor, @ShellBackgroundThread ShellExecutor bgExecutor, Choreographer choreographer, SyncTransactionQueue syncQueue, @@ -97,6 +102,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL super(context, userContext, displayController, taskOrganizer, taskInfo, taskSurface, windowDecorViewHostSupplier); mHandler = handler; + mMainExecutor = mainExecutor; mBgExecutor = bgExecutor; mChoreographer = choreographer; mSyncQueue = syncQueue; @@ -287,8 +293,14 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL if (oldDecorationSurface != mDecorationContainerSurface || mDragResizeListener == null) { closeDragResizeListener(); + final ShellExecutor bgExecutor = + DesktopModeFlags.ENABLE_DRAG_RESIZE_SET_UP_IN_BG_THREAD.isTrue() + ? mBgExecutor : mMainExecutor; mDragResizeListener = new DragResizeInputListener( mContext, + WindowManagerGlobal.getWindowSession(), + mMainExecutor, + bgExecutor, mTaskInfo, mHandler, mChoreographer, @@ -299,17 +311,19 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL mSurfaceControlTransactionSupplier, mDisplayController); } - + final DragResizeInputListener newListener = mDragResizeListener; final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()) .getScaledTouchSlop(); - final Resources res = mResult.mRootView.getResources(); - mDragResizeListener.setGeometry(new DragResizeWindowGeometry(0 /* taskCornerRadius */, - new Size(mResult.mWidth, mResult.mHeight), - getResizeEdgeHandleSize(res), - getResizeHandleEdgeInset(res), getFineResizeCornerSize(res), - getLargeResizeCornerSize(res), DragResizeWindowGeometry.DisabledEdge.NONE), - touchSlop); + final DragResizeWindowGeometry newGeometry = new DragResizeWindowGeometry( + 0 /* taskCornerRadius */, + new Size(mResult.mWidth, mResult.mHeight), + getResizeEdgeHandleSize(res), + getResizeHandleEdgeInset(res), getFineResizeCornerSize(res), + getLargeResizeCornerSize(res), DragResizeWindowGeometry.DisabledEdge.NONE); + newListener.addInitializedCallback(() -> { + mDragResizeListener.setGeometry(newGeometry, touchSlop); + }); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index a25289d0ea79..cf139a008164 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -103,6 +103,7 @@ import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController; import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; @@ -258,6 +259,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, private final RecentsTransitionHandler mRecentsTransitionHandler; private final DesktopModeCompatPolicy mDesktopModeCompatPolicy; private final DesktopTilingDecorViewModel mDesktopTilingDecorViewModel; + private final MultiDisplayDragMoveIndicatorController mMultiDisplayDragMoveIndicatorController; public DesktopModeWindowDecorViewModel( Context context, @@ -296,7 +298,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, WindowDecorTaskResourceLoader taskResourceLoader, RecentsTransitionHandler recentsTransitionHandler, DesktopModeCompatPolicy desktopModeCompatPolicy, - DesktopTilingDecorViewModel desktopTilingDecorViewModel) { + DesktopTilingDecorViewModel desktopTilingDecorViewModel, + MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController) { this( context, shellExecutor, @@ -340,7 +343,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy, - desktopTilingDecorViewModel); + desktopTilingDecorViewModel, + multiDisplayDragMoveIndicatorController); } @VisibleForTesting @@ -387,7 +391,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, WindowDecorTaskResourceLoader taskResourceLoader, RecentsTransitionHandler recentsTransitionHandler, DesktopModeCompatPolicy desktopModeCompatPolicy, - DesktopTilingDecorViewModel desktopTilingDecorViewModel) { + DesktopTilingDecorViewModel desktopTilingDecorViewModel, + MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController) { mContext = context; mMainExecutor = shellExecutor; mMainHandler = mainHandler; @@ -460,6 +465,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mDesktopModeCompatPolicy = desktopModeCompatPolicy; mDesktopTilingDecorViewModel = desktopTilingDecorViewModel; mDesktopTasksController.setSnapEventHandler(this); + mMultiDisplayDragMoveIndicatorController = multiDisplayDragMoveIndicatorController; shellInit.addInitCallback(this::onInit, this); } @@ -1531,7 +1537,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, // Do not create an indicator at all if we're not past transition height. DisplayLayout layout = mDisplayController .getDisplayLayout(relevantDecor.mTaskInfo.displayId); - if (ev.getRawY() < 2 * layout.stableInsets().top + // It's possible task is not at the top of the screen (e.g. bottom of vertical + // Splitscreen) + final int taskTop = relevantDecor.mTaskInfo.configuration.windowConfiguration + .getBounds().top; + if (ev.getRawY() < 2 * layout.stableInsets().top + taskTop && mMoveToDesktopAnimator == null) { return; } @@ -1755,7 +1765,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, mTransitions, mInteractionJankMonitor, mTransactionFactory, - mMainHandler); + mMainHandler, + mMultiDisplayDragMoveIndicatorController); windowDecoration.setTaskDragResizer(taskPositioner); final DesktopModeTouchEventListener touchEventListener = @@ -2052,7 +2063,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, Transitions transitions, InteractionJankMonitor interactionJankMonitor, Supplier<SurfaceControl.Transaction> transactionFactory, - Handler handler) { + Handler handler, + MultiDisplayDragMoveIndicatorController multiDisplayDragMoveIndicatorController) { final TaskPositioner taskPositioner = DesktopModeStatus.isVeiledResizeEnabled() // TODO(b/383632995): Update when the flag is launched. ? (Flags.enableConnectedDisplaysWindowDrag() @@ -2063,7 +2075,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, dragEventListener, transitions, interactionJankMonitor, - handler) + handler, + multiDisplayDragMoveIndicatorController) : new VeiledResizeTaskPositioner( taskOrganizer, windowDecoration, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 271dead467b4..dca376f7df0e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -68,6 +68,7 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.WindowInsets; import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.widget.ImageButton; import android.window.DesktopModeFlags; import android.window.TaskSnapshot; @@ -479,7 +480,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin if (shouldDelayUpdate) { return; } - updateDragResizeListener(mDecorationContainerSurface, inFullImmersive); + updateDragResizeListenerIfNeeded(mDecorationContainerSurface, inFullImmersive); } @@ -587,7 +588,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin closeMaximizeMenu(); notifyNoCaptionHandle(); } - updateDragResizeListener(oldDecorationSurface, inFullImmersive); + updateDragResizeListenerIfNeeded(oldDecorationSurface, inFullImmersive); updateMaximizeMenu(startT, inFullImmersive); Trace.endSection(); // DesktopModeWindowDecoration#relayout } @@ -665,22 +666,42 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return mUserContext.getUser(); } - private void updateDragResizeListener(SurfaceControl oldDecorationSurface, + private void updateDragResizeListenerIfNeeded(@Nullable SurfaceControl containerSurface, boolean inFullImmersive) { + final boolean taskPositionChanged = !mTaskInfo.positionInParent.equals(mPositionInParent); if (!isDragResizable(mTaskInfo, inFullImmersive)) { - if (!mTaskInfo.positionInParent.equals(mPositionInParent)) { + if (taskPositionChanged) { // We still want to track caption bar's exclusion region on a non-resizeable task. updateExclusionRegion(inFullImmersive); } closeDragResizeListener(); return; } + updateDragResizeListener(containerSurface, + (geometryChanged) -> { + if (geometryChanged || taskPositionChanged) { + updateExclusionRegion(inFullImmersive); + } + }); + } - if (oldDecorationSurface != mDecorationContainerSurface || mDragResizeListener == null) { + private void updateDragResizeListener(@Nullable SurfaceControl containerSurface, + Consumer<Boolean> onUpdateFinished) { + final boolean containerSurfaceChanged = containerSurface != mDecorationContainerSurface; + final boolean isFirstDragResizeListener = mDragResizeListener == null; + final boolean shouldCreateListener = containerSurfaceChanged || isFirstDragResizeListener; + if (containerSurfaceChanged) { closeDragResizeListener(); - Trace.beginSection("DesktopModeWindowDecoration#relayout-DragResizeInputListener"); + } + if (shouldCreateListener) { + final ShellExecutor bgExecutor = + DesktopModeFlags.ENABLE_DRAG_RESIZE_SET_UP_IN_BG_THREAD.isTrue() + ? mBgExecutor : mMainExecutor; mDragResizeListener = new DragResizeInputListener( mContext, + WindowManagerGlobal.getWindowSession(), + mMainExecutor, + bgExecutor, mTaskInfo, mHandler, mChoreographer, @@ -691,24 +712,20 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mSurfaceControlTransactionSupplier, mDisplayController, mDesktopModeEventLogger); - Trace.endSection(); } - + final DragResizeInputListener newListener = mDragResizeListener; final int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()) .getScaledTouchSlop(); - - // If either task geometry or position have changed, update this task's - // exclusion region listener final Resources res = mResult.mRootView.getResources(); - if (mDragResizeListener.setGeometry( - new DragResizeWindowGeometry(mRelayoutParams.mCornerRadius, - new Size(mResult.mWidth, mResult.mHeight), - getResizeEdgeHandleSize(res), getResizeHandleEdgeInset(res), - getFineResizeCornerSize(res), getLargeResizeCornerSize(res), - mDisabledResizingEdge), touchSlop) - || !mTaskInfo.positionInParent.equals(mPositionInParent)) { - updateExclusionRegion(inFullImmersive); - } + final DragResizeWindowGeometry newGeometry = new DragResizeWindowGeometry( + mRelayoutParams.mCornerRadius, + new Size(mResult.mWidth, mResult.mHeight), + getResizeEdgeHandleSize(res), getResizeHandleEdgeInset(res), + getFineResizeCornerSize(res), getLargeResizeCornerSize(res), + mDisabledResizingEdge); + newListener.addInitializedCallback(() -> { + onUpdateFinished.accept(newListener.setGeometry(newGeometry, touchSlop)); + }); } private static boolean isDragResizable(ActivityManager.RunningTaskInfo taskInfo, @@ -1711,7 +1728,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin */ private Region getGlobalExclusionRegion(boolean inFullImmersive) { Region exclusionRegion; - if (mDragResizeListener != null && isDragResizable(mTaskInfo, inFullImmersive)) { + if (mDragResizeListener != null + && isDragResizable(mTaskInfo, inFullImmersive)) { exclusionRegion = mDragResizeListener.getCornersRegion(); } else { exclusionRegion = new Region(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java index b531079f18c1..7a4a834e9dc2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java @@ -43,6 +43,7 @@ import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; +import android.os.Trace; import android.util.Size; import android.view.Choreographer; import android.view.IWindowSession; @@ -54,14 +55,19 @@ import android.view.PointerIcon; import android.view.SurfaceControl; import android.view.View; import android.view.ViewConfiguration; -import android.view.WindowManagerGlobal; import android.window.InputTransferToken; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.ProtoLog; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; +import com.android.wm.shell.shared.annotations.ShellBackgroundThread; +import com.android.wm.shell.shared.annotations.ShellMainThread; +import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; import java.util.function.Supplier; @@ -73,28 +79,45 @@ import java.util.function.Supplier; */ class DragResizeInputListener implements AutoCloseable { private static final String TAG = "DragResizeInputListener"; - private final IWindowSession mWindowSession = WindowManagerGlobal.getWindowSession(); + private final IWindowSession mWindowSession; + private final TaskResizeInputEventReceiverFactory mEventReceiverFactory; + private final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier; private final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier; private final int mDisplayId; - private final IBinder mClientToken; + @VisibleForTesting + final IBinder mClientToken; private final SurfaceControl mDecorationSurface; - private final InputChannel mInputChannel; - private final TaskResizeInputEventReceiver mInputEventReceiver; + private InputChannel mInputChannel; + private TaskResizeInputEventReceiver mInputEventReceiver; private final Context mContext; + private final @ShellBackgroundThread ShellExecutor mBgExecutor; private final RunningTaskInfo mTaskInfo; - private final SurfaceControl mInputSinkSurface; - private final IBinder mSinkClientToken; - private final InputChannel mSinkInputChannel; + private final Handler mHandler; + private final Choreographer mChoreographer; + private SurfaceControl mInputSinkSurface; + @VisibleForTesting + final IBinder mSinkClientToken; + private InputChannel mSinkInputChannel; private final DisplayController mDisplayController; + /** TODO: b/396490344 - this desktop-specific class should be abstracted out of here. */ private final DesktopModeEventLogger mDesktopModeEventLogger; + private final DragPositioningCallback mDragPositioningCallback; private final Region mTouchRegion = new Region(); + private final List<Runnable> mOnInitializedCallbacks = new ArrayList<>(); + + private final Runnable mInitInputChannels; + private boolean mClosed = false; DragResizeInputListener( Context context, + IWindowSession windowSession, + @ShellMainThread ShellExecutor mainExecutor, + @ShellBackgroundThread ShellExecutor bgExecutor, + TaskResizeInputEventReceiverFactory eventReceiverFactory, RunningTaskInfo taskInfo, Handler handler, Choreographer choreographer, @@ -106,20 +129,138 @@ class DragResizeInputListener implements AutoCloseable { DisplayController displayController, DesktopModeEventLogger desktopModeEventLogger) { mContext = context; + mWindowSession = windowSession; + mBgExecutor = bgExecutor; + mEventReceiverFactory = eventReceiverFactory; mTaskInfo = taskInfo; - mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier; + mHandler = handler; + mChoreographer = choreographer; mDisplayId = displayId; mDecorationSurface = decorationSurface; + mDragPositioningCallback = callback; + mSurfaceControlBuilderSupplier = surfaceControlBuilderSupplier; + mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier; mDisplayController = displayController; mDesktopModeEventLogger = desktopModeEventLogger; mClientToken = new Binder(); + mSinkClientToken = new Binder(); + + // Setting up input channels for both the resize listener and the input sink requires + // multiple blocking binder calls, so it's moved to a bg thread to keep the shell.main + // thread free. + // The input event receiver must be created back in the shell.main thread though because + // its geometry and util methods are updated/queried from the shell.main thread. + mInitInputChannels = () -> { + final InputSetUpResult result = setUpInputChannels(mDisplayId, mWindowSession, + mDecorationSurface, mClientToken, mSinkClientToken, + mSurfaceControlBuilderSupplier, + mSurfaceControlTransactionSupplier); + mainExecutor.execute(() -> { + if (mClosed) { + return; + } + mInputSinkSurface = result.mInputSinkSurface; + mInputChannel = result.mInputChannel; + mSinkInputChannel = result.mSinkInputChannel; + Trace.beginSection("DragResizeInputListener#ctor-initReceiver"); + mInputEventReceiver = mEventReceiverFactory.create( + mContext, + mTaskInfo, + mInputChannel, + mDragPositioningCallback, + mHandler, + mChoreographer, + () -> { + final DisplayLayout layout = + mDisplayController.getDisplayLayout(mDisplayId); + return new Size(layout.width(), layout.height()); + }, + this::updateSinkInputChannel, + mDesktopModeEventLogger); + mInputEventReceiver.setTouchSlop( + ViewConfiguration.get(mContext).getScaledTouchSlop()); + for (Runnable initCallback : mOnInitializedCallbacks) { + initCallback.run(); + } + mOnInitializedCallbacks.clear(); + Trace.endSection(); + }); + }; + bgExecutor.execute(mInitInputChannels); + } + + DragResizeInputListener( + Context context, + IWindowSession windowSession, + @ShellMainThread ShellExecutor mainExecutor, + @ShellBackgroundThread ShellExecutor bgExecutor, + RunningTaskInfo taskInfo, + Handler handler, + Choreographer choreographer, + int displayId, + SurfaceControl decorationSurface, + DragPositioningCallback callback, + Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, + Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier, + DisplayController displayController, + DesktopModeEventLogger desktopModeEventLogger) { + this(context, windowSession, mainExecutor, bgExecutor, + new DefaultTaskResizeInputEventReceiverFactory(), taskInfo, + handler, choreographer, displayId, decorationSurface, callback, + surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, + displayController, desktopModeEventLogger); + } + + DragResizeInputListener( + Context context, + IWindowSession windowSession, + @ShellMainThread ShellExecutor mainExecutor, + @ShellBackgroundThread ShellExecutor bgExecutor, + RunningTaskInfo taskInfo, + Handler handler, + Choreographer choreographer, + int displayId, + SurfaceControl decorationSurface, + DragPositioningCallback callback, + Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, + Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier, + DisplayController displayController) { + this(context, windowSession, mainExecutor, bgExecutor, taskInfo, + handler, choreographer, displayId, decorationSurface, callback, + surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, + displayController, new DesktopModeEventLogger()); + } + + /** + * Registers a callback to be invoked when the input listener has finished initializing. If + * already finished, the callback will be invoked immediately. + */ + void addInitializedCallback(Runnable onReady) { + if (mInputEventReceiver != null) { + onReady.run(); + return; + } + mOnInitializedCallbacks.add(onReady); + } + + @ShellBackgroundThread + private static InputSetUpResult setUpInputChannels( + int displayId, + @NonNull IWindowSession windowSession, + @NonNull SurfaceControl decorationSurface, + @NonNull IBinder clientToken, + @NonNull IBinder sinkClientToken, + @NonNull Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, + @NonNull Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier) { + Trace.beginSection("DragResizeInputListener#setUpInputChannels"); final InputTransferToken inputTransferToken = new InputTransferToken(); - mInputChannel = new InputChannel(); + final InputChannel inputChannel = new InputChannel(); + final InputChannel sinkInputChannel = new InputChannel(); try { - mWindowSession.grantInputChannel( - mDisplayId, - mDecorationSurface, - mClientToken, + windowSession.grantInputChannel( + displayId, + decorationSurface, + clientToken, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, PRIVATE_FLAG_TRUSTED_OVERLAY, @@ -127,37 +268,27 @@ class DragResizeInputListener implements AutoCloseable { TYPE_APPLICATION, null /* windowToken */, inputTransferToken, - TAG + " of " + decorationSurface.toString(), - mInputChannel); + TAG + " of " + decorationSurface, + inputChannel); } catch (RemoteException e) { e.rethrowFromSystemServer(); } - mInputEventReceiver = new TaskResizeInputEventReceiver(context, mTaskInfo, mInputChannel, - callback, - handler, choreographer, () -> { - final DisplayLayout layout = mDisplayController.getDisplayLayout(mDisplayId); - return new Size(layout.width(), layout.height()); - }, this::updateSinkInputChannel, mDesktopModeEventLogger); - mInputEventReceiver.setTouchSlop(ViewConfiguration.get(context).getScaledTouchSlop()); - - mInputSinkSurface = surfaceControlBuilderSupplier.get() + final SurfaceControl inputSinkSurface = surfaceControlBuilderSupplier.get() .setName("TaskInputSink of " + decorationSurface) .setContainerLayer() - .setParent(mDecorationSurface) - .setCallsite("DragResizeInputListener.constructor") + .setParent(decorationSurface) + .setCallsite("DragResizeInputListener.setUpInputChannels") .build(); - mSurfaceControlTransactionSupplier.get() - .setLayer(mInputSinkSurface, WindowDecoration.INPUT_SINK_Z_ORDER) - .show(mInputSinkSurface) + surfaceControlTransactionSupplier.get() + .setLayer(inputSinkSurface, WindowDecoration.INPUT_SINK_Z_ORDER) + .show(inputSinkSurface) .apply(); - mSinkClientToken = new Binder(); - mSinkInputChannel = new InputChannel(); try { - mWindowSession.grantInputChannel( - mDisplayId, - mInputSinkSurface, - mSinkClientToken, + windowSession.grantInputChannel( + displayId, + inputSinkSurface, + sinkClientToken, null /* hostInputToken */, FLAG_NOT_FOCUSABLE, 0 /* privateFlags */, @@ -166,26 +297,12 @@ class DragResizeInputListener implements AutoCloseable { null /* windowToken */, inputTransferToken, "TaskInputSink of " + decorationSurface, - mSinkInputChannel); + sinkInputChannel); } catch (RemoteException e) { e.rethrowFromSystemServer(); } - } - - DragResizeInputListener( - Context context, - RunningTaskInfo taskInfo, - Handler handler, - Choreographer choreographer, - int displayId, - SurfaceControl decorationSurface, - DragPositioningCallback callback, - Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier, - Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier, - DisplayController displayController) { - this(context, taskInfo, handler, choreographer, displayId, decorationSurface, callback, - surfaceControlBuilderSupplier, surfaceControlTransactionSupplier, displayController, - new DesktopModeEventLogger()); + Trace.endSection(); + return new InputSetUpResult(inputSinkSurface, inputChannel, sinkInputChannel); } /** @@ -268,35 +385,101 @@ class DragResizeInputListener implements AutoCloseable { } boolean shouldHandleEvent(@NonNull MotionEvent e, @NonNull Point offset) { - return mInputEventReceiver.shouldHandleEvent(e, offset); + return mInputEventReceiver != null && mInputEventReceiver.shouldHandleEvent(e, offset); } boolean isHandlingDragResize() { - return mInputEventReceiver.isHandlingEvents(); + return mInputEventReceiver != null && mInputEventReceiver.isHandlingEvents(); } @Override public void close() { - mInputEventReceiver.dispose(); - mInputChannel.dispose(); - try { - mWindowSession.remove(mClientToken); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); + mClosed = true; + if (mInitInputChannels != null) { + mBgExecutor.removeCallbacks(mInitInputChannels); + } + if (mInputEventReceiver != null) { + mInputEventReceiver.dispose(); + } + if (mInputChannel != null) { + mInputChannel.dispose(); + } + if (mSinkInputChannel != null) { + mSinkInputChannel.dispose(); } - mSinkInputChannel.dispose(); - try { - mWindowSession.remove(mSinkClientToken); - } catch (RemoteException e) { - e.rethrowFromSystemServer(); + if (mInputSinkSurface != null) { + mSurfaceControlTransactionSupplier.get() + .remove(mInputSinkSurface) + .apply(); } - mSurfaceControlTransactionSupplier.get() - .remove(mInputSinkSurface) - .apply(); + + mBgExecutor.execute(() -> { + try { + mWindowSession.remove(mClientToken); + mWindowSession.remove(mSinkClientToken); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + }); } - private static class TaskResizeInputEventReceiver extends InputEventReceiver implements + private static class InputSetUpResult { + final @NonNull SurfaceControl mInputSinkSurface; + final @NonNull InputChannel mInputChannel; + final @NonNull InputChannel mSinkInputChannel; + + InputSetUpResult(@NonNull SurfaceControl inputSinkSurface, + @NonNull InputChannel inputChannel, + @NonNull InputChannel sinkInputChannel) { + mInputSinkSurface = inputSinkSurface; + mInputChannel = inputChannel; + mSinkInputChannel = sinkInputChannel; + } + } + + /** A factory that creates {@link TaskResizeInputEventReceiver}s. */ + interface TaskResizeInputEventReceiverFactory { + @NonNull + TaskResizeInputEventReceiver create( + @NonNull Context context, + @NonNull RunningTaskInfo taskInfo, + @NonNull InputChannel inputChannel, + @NonNull DragPositioningCallback callback, + @NonNull Handler handler, + @NonNull Choreographer choreographer, + @NonNull Supplier<Size> displayLayoutSizeSupplier, + @NonNull Consumer<Region> touchRegionConsumer, + @NonNull DesktopModeEventLogger desktopModeEventLogger + ); + } + + /** A default implementation of {@link TaskResizeInputEventReceiverFactory}. */ + static class DefaultTaskResizeInputEventReceiverFactory + implements TaskResizeInputEventReceiverFactory { + @Override + @NonNull + public TaskResizeInputEventReceiver create( + @NonNull Context context, + @NonNull RunningTaskInfo taskInfo, + @NonNull InputChannel inputChannel, + @NonNull DragPositioningCallback callback, + @NonNull Handler handler, + @NonNull Choreographer choreographer, + @NonNull Supplier<Size> displayLayoutSizeSupplier, + @NonNull Consumer<Region> touchRegionConsumer, + @NonNull DesktopModeEventLogger desktopModeEventLogger) { + return new TaskResizeInputEventReceiver(context, taskInfo, inputChannel, callback, + handler, choreographer, displayLayoutSizeSupplier, touchRegionConsumer, + desktopModeEventLogger); + } + } + + /** + * An input event receiver to handle motion events on the task's corners and edges for + * drag-resizing, as well as keeping the input sink updated. + */ + static class TaskResizeInputEventReceiver extends InputEventReceiver implements DragDetector.MotionEventHandler { @NonNull private final Context mContext; @NonNull private final RunningTaskInfo mTaskInfo; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt index bb20292a51d4..c6cb62d153ac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositioner.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.windowdecor import android.graphics.PointF import android.graphics.Rect +import android.hardware.display.DisplayTopology import android.os.Handler import android.os.IBinder import android.os.Looper @@ -32,10 +33,10 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.MultiDisplayDragMoveBoundsCalculator +import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.transition.Transitions import java.util.concurrent.TimeUnit -import java.util.function.Supplier /** * A task positioner that also takes into account resizing a @@ -49,11 +50,12 @@ class MultiDisplayVeiledResizeTaskPositioner( private val desktopWindowDecoration: DesktopModeWindowDecoration, private val displayController: DisplayController, dragEventListener: DragPositioningCallbackUtility.DragEventListener, - private val transactionSupplier: Supplier<SurfaceControl.Transaction>, + private val transactionSupplier: () -> SurfaceControl.Transaction, private val transitions: Transitions, private val interactionJankMonitor: InteractionJankMonitor, @ShellMainThread private val handler: Handler, -) : TaskPositioner, Transitions.TransitionHandler { + private val multiDisplayDragMoveIndicatorController: MultiDisplayDragMoveIndicatorController, +) : TaskPositioner, Transitions.TransitionHandler, DisplayController.OnDisplaysChangedListener { private val dragEventListeners = mutableListOf<DragPositioningCallbackUtility.DragEventListener>() private val stableBounds = Rect() @@ -71,6 +73,7 @@ class MultiDisplayVeiledResizeTaskPositioner( private var isResizingOrAnimatingResize = false @Surface.Rotation private var rotation = 0 private var startDisplayId = 0 + private val displayIds = mutableSetOf<Int>() constructor( taskOrganizer: ShellTaskOrganizer, @@ -80,19 +83,22 @@ class MultiDisplayVeiledResizeTaskPositioner( transitions: Transitions, interactionJankMonitor: InteractionJankMonitor, @ShellMainThread handler: Handler, + multiDisplayDragMoveIndicatorController: MultiDisplayDragMoveIndicatorController, ) : this( taskOrganizer, windowDecoration, displayController, dragEventListener, - Supplier<SurfaceControl.Transaction> { SurfaceControl.Transaction() }, + { SurfaceControl.Transaction() }, transitions, interactionJankMonitor, handler, + multiDisplayDragMoveIndicatorController, ) init { dragEventListeners.add(dragEventListener) + displayController.addDisplayWindowListener(this) } override fun onDragPositioningStart(ctrlType: Int, displayId: Int, x: Float, y: Float): Rect { @@ -164,7 +170,7 @@ class MultiDisplayVeiledResizeTaskPositioner( createLongTimeoutJankConfigBuilder(Cuj.CUJ_DESKTOP_MODE_DRAG_WINDOW) ) - val t = transactionSupplier.get() + val t = transactionSupplier() val startDisplayLayout = displayController.getDisplayLayout(startDisplayId) val currentDisplayLayout = displayController.getDisplayLayout(displayId) @@ -196,7 +202,13 @@ class MultiDisplayVeiledResizeTaskPositioner( ) ) - // TODO(b/383069173): Render drag indicator(s) + multiDisplayDragMoveIndicatorController.onDragMove( + boundsDp, + startDisplayId, + desktopWindowDecoration.mTaskInfo, + displayIds, + transactionSupplier, + ) t.setPosition( desktopWindowDecoration.leash, @@ -267,7 +279,10 @@ class MultiDisplayVeiledResizeTaskPositioner( ) ) - // TODO(b/383069173): Clear drag indicator(s) + multiDisplayDragMoveIndicatorController.onDragEnd( + desktopWindowDecoration.mTaskInfo.taskId, + transactionSupplier, + ) } interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_DRAG_WINDOW) @@ -348,6 +363,14 @@ class MultiDisplayVeiledResizeTaskPositioner( dragEventListeners.remove(dragEventListener) } + override fun onTopologyChanged(topology: DisplayTopology) { + // TODO: b/383069173 - Cancel window drag when topology changes happen during drag. + + displayIds.clear() + val displayBounds = topology.getAbsoluteBounds() + displayIds.addAll(List(displayBounds.size()) { displayBounds.keyAt(it) }) + } + companion object { // Timeout used for resize and drag CUJs, this is longer than the default timeout to avoid // timing out in the middle of a resize or drag action. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt index 88cc94ca8728..7af6b8e26cbf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.kt @@ -90,6 +90,7 @@ public class ResizeVeil @JvmOverloads constructor( private var viewHost: SurfaceControlViewHost? = null private var display: Display? = null private var veilAnimator: ValueAnimator? = null + private var iconAnimator: ValueAnimator? = null private var loadAppInfoJob: Job? = null /** @@ -241,7 +242,7 @@ public class ResizeVeil @JvmOverloads constructor( } }) } - val iconAnimator = ValueAnimator.ofFloat(0f, 1f).apply { + iconAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = RESIZE_ALPHA_DURATION addUpdateListener { iconAnimT.setAlpha(icon, animatedValue as Float) @@ -265,7 +266,7 @@ public class ResizeVeil @JvmOverloads constructor( .hide(background) .apply() veilAnimator?.start() - iconAnimator.start() + iconAnimator?.start() } else { // Show the veil immediately. t.apply() @@ -414,6 +415,10 @@ public class ResizeVeil @JvmOverloads constructor( private fun cancelAnimation() { veilAnimator?.removeAllUpdateListeners() veilAnimator?.cancel() + veilAnimator = null + iconAnimator?.removeAllUpdateListeners() + iconAnimator?.cancel() + iconAnimator = null } /** @@ -421,7 +426,6 @@ public class ResizeVeil @JvmOverloads constructor( */ fun dispose() { cancelAnimation() - veilAnimator = null isVisible = false loadAppInfoJob?.cancel() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt index 4a09614029dc..a5592f81a39e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt @@ -50,9 +50,8 @@ class ReusableWindowDecorViewHost( @VisibleForTesting val viewHostAdapter: SurfaceControlViewHostAdapter = SurfaceControlViewHostAdapter(context, display), + private val rootView: FrameLayout = FrameLayout(context) ) : WindowDecorViewHost, Warmable { - @VisibleForTesting val rootView = FrameLayout(context) - private var currentUpdateJob: Job? = null override val surfaceControl: SurfaceControl @@ -131,8 +130,10 @@ class ReusableWindowDecorViewHost( Trace.beginSection("ReusableWindowDecorViewHost#updateViewHost") viewHostAdapter.prepareViewHost(configuration, touchableRegion) onDrawTransaction?.let { viewHostAdapter.applyTransactionOnDraw(it) } - rootView.removeAllViews() - rootView.addView(view) + if (view.parent != rootView) { + rootView.removeAllViews() + rootView.addView(view) + } viewHostAdapter.updateView(rootView, attrs) Trace.endSection() } diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt index 2115f70faad0..af2840e9c34a 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt @@ -45,6 +45,7 @@ constructor( tapl.setExpectedRotation(rotation.value) ChangeDisplayOrientationRule.setRotation(rotation) tapl.enableTransientTaskbar(false) + testApp.exit(wmHelper) } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp index bf5e374c7607..bff12d026b93 100644 --- a/libs/WindowManager/Shell/tests/unittest/Android.bp +++ b/libs/WindowManager/Shell/tests/unittest/Android.bp @@ -45,6 +45,7 @@ android_test { "androidx.test.rules", "androidx.test.ext.junit", "androidx.datastore_datastore", + "androidx.core_core-animation-testing", "kotlinx_coroutines_test", "androidx.dynamicanimation_dynamicanimation", "dagger2", diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorControllerTest.kt new file mode 100644 index 000000000000..abd238847519 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/MultiDisplayDragMoveIndicatorControllerTest.kt @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.common + +import android.app.ActivityManager.RunningTaskInfo +import android.content.res.Configuration +import android.graphics.Rect +import android.graphics.RectF +import android.testing.TestableResources +import android.view.Display +import android.view.SurfaceControl +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestShellExecutor +import java.util.function.Supplier +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.times +import org.mockito.kotlin.whenever + +/** + * Tests for [MultiDisplayDragMoveIndicatorController]. + * + * Build/Install/Run: atest WMShellUnitTests:MultiDisplayDragMoveIndicatorControllerTest + */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class MultiDisplayDragMoveIndicatorControllerTest : ShellTestCase() { + private val displayController = mock<DisplayController>() + private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>() + private val indicatorSurfaceFactory = mock<MultiDisplayDragMoveIndicatorSurface.Factory>() + private val indicatorSurface0 = mock<MultiDisplayDragMoveIndicatorSurface>() + private val indicatorSurface1 = mock<MultiDisplayDragMoveIndicatorSurface>() + private val transaction = mock<SurfaceControl.Transaction>() + private val transactionSupplier = mock<Supplier<SurfaceControl.Transaction>>() + private val taskInfo = mock<RunningTaskInfo>() + private val display0 = mock<Display>() + private val display1 = mock<Display>() + + private lateinit var resources: TestableResources + private val executor = TestShellExecutor() + + private lateinit var controller: MultiDisplayDragMoveIndicatorController + + @Before + fun setUp() { + resources = mContext.getOrCreateTestableResources() + val resourceConfiguration = Configuration() + resourceConfiguration.uiMode = 0 + resources.overrideConfiguration(resourceConfiguration) + + controller = + MultiDisplayDragMoveIndicatorController( + displayController, + rootTaskDisplayAreaOrganizer, + indicatorSurfaceFactory, + executor, + ) + + val spyDisplayLayout0 = + MultiDisplayTestUtil.createSpyDisplayLayout( + MultiDisplayTestUtil.DISPLAY_GLOBAL_BOUNDS_0, + MultiDisplayTestUtil.DISPLAY_DPI_0, + resources.resources, + ) + val spyDisplayLayout1 = + MultiDisplayTestUtil.createSpyDisplayLayout( + MultiDisplayTestUtil.DISPLAY_GLOBAL_BOUNDS_1, + MultiDisplayTestUtil.DISPLAY_DPI_1, + resources.resources, + ) + + taskInfo.taskId = TASK_ID + whenever(displayController.getDisplayLayout(0)).thenReturn(spyDisplayLayout0) + whenever(displayController.getDisplayLayout(1)).thenReturn(spyDisplayLayout1) + whenever(displayController.getDisplay(0)).thenReturn(display0) + whenever(displayController.getDisplay(1)).thenReturn(display1) + whenever(indicatorSurfaceFactory.create(taskInfo, display0)).thenReturn(indicatorSurface0) + whenever(indicatorSurfaceFactory.create(taskInfo, display1)).thenReturn(indicatorSurface1) + whenever(transactionSupplier.get()).thenReturn(transaction) + } + + @Test + fun onDrag_boundsNotIntersectWithDisplay_noIndicator() { + controller.onDragMove( + RectF(2000f, 2000f, 2100f, 2200f), // not intersect with any display + startDisplayId = 0, + taskInfo, + displayIds = setOf(0, 1), + ) { transaction } + executor.flushAll() + + verify(indicatorSurfaceFactory, never()).create(any(), any()) + } + + @Test + fun onDrag_boundsIntersectWithStartDisplay_noIndicator() { + controller.onDragMove( + RectF(100f, 100f, 200f, 200f), // intersect with display 0 + startDisplayId = 0, + taskInfo, + displayIds = setOf(0, 1), + ) { transaction } + executor.flushAll() + + verify(indicatorSurfaceFactory, never()).create(any(), any()) + } + + @Test + fun onDrag_boundsIntersectWithNonStartDisplay_showAndDisposeIndicator() { + controller.onDragMove( + RectF(100f, -100f, 200f, 200f), // intersect with display 0 and 1 + startDisplayId = 0, + taskInfo, + displayIds = setOf(0, 1), + ) { transaction } + executor.flushAll() + + verify(indicatorSurfaceFactory, times(1)).create(taskInfo, display1) + verify(indicatorSurface1, times(1)) + .show(transaction, taskInfo, rootTaskDisplayAreaOrganizer, 1, Rect(0, 1800, 200, 2400)) + + controller.onDragMove( + RectF(2000f, 2000f, 2100f, 2200f), // not intersect with display 1 + startDisplayId = 0, + taskInfo, + displayIds = setOf(0, 1) + ) { transaction } + while (executor.callbacks.isNotEmpty()) { + executor.flushAll() + } + + verify(indicatorSurface1, times(1)) + .relayout(any(), eq(transaction), shouldBeVisible = eq(false)) + + controller.onDragEnd(TASK_ID, { transaction }) + while (executor.callbacks.isNotEmpty()) { + executor.flushAll() + } + + verify(indicatorSurface1, times(1)).disposeSurface(transaction) + } + + companion object { + private const val TASK_ID = 10 + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt index 0d5741fccbcc..8ad54f5a0bb4 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayEventHandlerTest.kt @@ -16,51 +16,28 @@ package com.android.wm.shell.desktopmode -import android.app.ActivityManager.RunningTaskInfo -import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM -import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN -import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED -import android.content.ContentResolver -import android.os.Binder import android.platform.test.annotations.EnableFlags -import android.provider.Settings -import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY -import android.view.IWindowManager -import android.view.WindowManager.TRANSIT_CHANGE -import android.window.DisplayAreaInfo -import android.window.WindowContainerTransaction import androidx.test.filters.SmallTest import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.never import com.android.dx.mockito.inline.extended.StaticMockitoSession import com.android.window.flags.Flags -import com.android.wm.shell.MockToken -import com.android.wm.shell.RootTaskDisplayAreaOrganizer -import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase -import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayController.OnDisplaysChangedListener import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.sysui.ShellInit -import com.android.wm.shell.transition.Transitions -import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers.isNull import org.mockito.Mock -import org.mockito.Mockito.anyInt import org.mockito.Mockito.spy -import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.eq import org.mockito.kotlin.whenever import org.mockito.quality.Strictness @@ -73,27 +50,18 @@ import org.mockito.quality.Strictness @RunWith(AndroidTestingRunner::class) class DesktopDisplayEventHandlerTest : ShellTestCase() { @Mock lateinit var testExecutor: ShellExecutor - @Mock lateinit var transitions: Transitions @Mock lateinit var displayController: DisplayController - @Mock lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer - @Mock private lateinit var mockWindowManager: IWindowManager @Mock private lateinit var mockDesktopUserRepositories: DesktopUserRepositories @Mock private lateinit var mockDesktopRepository: DesktopRepository @Mock private lateinit var mockDesktopTasksController: DesktopTasksController - @Mock private lateinit var shellTaskOrganizer: ShellTaskOrganizer + @Mock private lateinit var desktopDisplayModeController: DesktopDisplayModeController private lateinit var mockitoSession: StaticMockitoSession private lateinit var shellInit: ShellInit private lateinit var handler: DesktopDisplayEventHandler private val onDisplaysChangedListenerCaptor = argumentCaptor<OnDisplaysChangedListener>() - private val runningTasks = mutableListOf<RunningTaskInfo>() private val externalDisplayId = 100 - private val freeformTask = - TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build() - private val fullscreenTask = - TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FULLSCREEN).build() - private val defaultTDA = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) @Before fun setUp() { @@ -105,24 +73,15 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { shellInit = spy(ShellInit(testExecutor)) whenever(mockDesktopUserRepositories.current).thenReturn(mockDesktopRepository) - whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() } - whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) - .thenReturn(defaultTDA) handler = DesktopDisplayEventHandler( context, shellInit, - transitions, displayController, - rootTaskDisplayAreaOrganizer, - mockWindowManager, mockDesktopUserRepositories, mockDesktopTasksController, - shellTaskOrganizer, + desktopDisplayModeController, ) - whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks } - runningTasks.add(freeformTask) - runningTasks.add(fullscreenTask) shellInit.init() verify(displayController) .addDisplayWindowListener(onDisplaysChangedListenerCaptor.capture()) @@ -133,65 +92,6 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { mockitoSession.finishMocking() } - private fun testDisplayWindowingModeSwitch( - defaultWindowingMode: Int, - extendedDisplayEnabled: Boolean, - expectTransition: Boolean, - ) { - defaultTDA.configuration.windowConfiguration.windowingMode = defaultWindowingMode - whenever(mockWindowManager.getWindowingMode(anyInt())).thenAnswer { defaultWindowingMode } - val settingsSession = - ExtendedDisplaySettingsSession( - context.contentResolver, - if (extendedDisplayEnabled) 1 else 0, - ) - - settingsSession.use { - connectExternalDisplay() - defaultTDA.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM - disconnectExternalDisplay() - - if (expectTransition) { - val arg = argumentCaptor<WindowContainerTransaction>() - verify(transitions, times(2)) - .startTransition(eq(TRANSIT_CHANGE), arg.capture(), isNull()) - assertThat(arg.firstValue.changes[defaultTDA.token.asBinder()]?.windowingMode) - .isEqualTo(WINDOWING_MODE_FREEFORM) - assertThat(arg.secondValue.changes[defaultTDA.token.asBinder()]?.windowingMode) - .isEqualTo(defaultWindowingMode) - } else { - verify(transitions, never()).startTransition(eq(TRANSIT_CHANGE), any(), isNull()) - } - } - } - - @Test - fun displayWindowingModeSwitchOnDisplayConnected_extendedDisplayDisabled() { - testDisplayWindowingModeSwitch( - defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, - extendedDisplayEnabled = false, - expectTransition = false, - ) - } - - @Test - fun displayWindowingModeSwitchOnDisplayConnected_fullscreenDisplay() { - testDisplayWindowingModeSwitch( - defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, - extendedDisplayEnabled = true, - expectTransition = true, - ) - } - - @Test - fun displayWindowingModeSwitchOnDisplayConnected_freeformDisplay() { - testDisplayWindowingModeSwitch( - defaultWindowingMode = WINDOWING_MODE_FREEFORM, - extendedDisplayEnabled = true, - expectTransition = false, - ) - } - @Test fun testDisplayAdded_supportsDesks_createsDesk() { whenever(DesktopModeStatus.canEnterDesktopMode(context)).thenReturn(true) @@ -231,70 +131,14 @@ class DesktopDisplayEventHandlerTest : ShellTestCase() { } @Test - fun displayWindowingModeSwitch_existingTasksOnConnected() { - defaultTDA.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN - whenever(mockWindowManager.getWindowingMode(anyInt())).thenAnswer { - WINDOWING_MODE_FULLSCREEN - } - - ExtendedDisplaySettingsSession(context.contentResolver, 1).use { - connectExternalDisplay() - - val arg = argumentCaptor<WindowContainerTransaction>() - verify(transitions, times(1)) - .startTransition(eq(TRANSIT_CHANGE), arg.capture(), isNull()) - assertThat(arg.firstValue.changes[freeformTask.token.asBinder()]?.windowingMode) - .isEqualTo(WINDOWING_MODE_UNDEFINED) - assertThat(arg.firstValue.changes[fullscreenTask.token.asBinder()]?.windowingMode) - .isEqualTo(WINDOWING_MODE_FULLSCREEN) - } - } - - @Test - fun displayWindowingModeSwitch_existingTasksOnDisconnected() { - defaultTDA.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM - whenever(mockWindowManager.getWindowingMode(anyInt())).thenAnswer { - WINDOWING_MODE_FULLSCREEN - } - - ExtendedDisplaySettingsSession(context.contentResolver, 1).use { - disconnectExternalDisplay() - - val arg = argumentCaptor<WindowContainerTransaction>() - verify(transitions, times(1)) - .startTransition(eq(TRANSIT_CHANGE), arg.capture(), isNull()) - assertThat(arg.firstValue.changes[freeformTask.token.asBinder()]?.windowingMode) - .isEqualTo(WINDOWING_MODE_FREEFORM) - assertThat(arg.firstValue.changes[fullscreenTask.token.asBinder()]?.windowingMode) - .isEqualTo(WINDOWING_MODE_UNDEFINED) - } - } - - private fun connectExternalDisplay() { - whenever(rootTaskDisplayAreaOrganizer.getDisplayIds()) - .thenReturn(intArrayOf(DEFAULT_DISPLAY, externalDisplayId)) + fun testConnectExternalDisplay() { onDisplaysChangedListenerCaptor.lastValue.onDisplayAdded(externalDisplayId) + verify(desktopDisplayModeController).refreshDisplayWindowingMode() } - private fun disconnectExternalDisplay() { - whenever(rootTaskDisplayAreaOrganizer.getDisplayIds()) - .thenReturn(intArrayOf(DEFAULT_DISPLAY)) + @Test + fun testDisconnectExternalDisplay() { onDisplaysChangedListenerCaptor.lastValue.onDisplayRemoved(externalDisplayId) - } - - private class ExtendedDisplaySettingsSession( - private val contentResolver: ContentResolver, - private val overrideValue: Int, - ) : AutoCloseable { - private val settingName = DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS - private val initialValue = Settings.Global.getInt(contentResolver, settingName, 0) - - init { - Settings.Global.putInt(contentResolver, settingName, overrideValue) - } - - override fun close() { - Settings.Global.putInt(contentResolver, settingName, initialValue) - } + verify(desktopDisplayModeController).refreshDisplayWindowingMode() } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt new file mode 100644 index 000000000000..0ff7230f6e0c --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopDisplayModeControllerTest.kt @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.desktopmode + +import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED +import android.content.ContentResolver +import android.os.Binder +import android.provider.Settings +import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS +import android.testing.AndroidTestingRunner +import android.view.Display.DEFAULT_DISPLAY +import android.view.IWindowManager +import android.view.WindowManager.TRANSIT_CHANGE +import android.window.DisplayAreaInfo +import android.window.WindowContainerTransaction +import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.never +import com.android.wm.shell.MockToken +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider +import com.android.wm.shell.transition.Transitions +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.isNull +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +/** + * Test class for [DesktopDisplayModeController] + * + * Usage: atest WMShellUnitTests:DesktopDisplayModeControllerTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class DesktopDisplayModeControllerTest : ShellTestCase() { + private val transitions = mock<Transitions>() + private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>() + private val mockWindowManager = mock<IWindowManager>() + private val shellTaskOrganizer = mock<ShellTaskOrganizer>() + private val desktopWallpaperActivityTokenProvider = + mock<DesktopWallpaperActivityTokenProvider>() + + private lateinit var controller: DesktopDisplayModeController + + private val runningTasks = mutableListOf<RunningTaskInfo>() + private val freeformTask = + TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FREEFORM).build() + private val fullscreenTask = + TestRunningTaskInfoBuilder().setWindowingMode(WINDOWING_MODE_FULLSCREEN).build() + private val defaultTDA = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) + private val wallpaperToken = MockToken().token() + + @Before + fun setUp() { + whenever(transitions.startTransition(anyInt(), any(), isNull())).thenReturn(Binder()) + whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) + .thenReturn(defaultTDA) + controller = + DesktopDisplayModeController( + context, + transitions, + rootTaskDisplayAreaOrganizer, + mockWindowManager, + shellTaskOrganizer, + desktopWallpaperActivityTokenProvider, + ) + runningTasks.add(freeformTask) + runningTasks.add(fullscreenTask) + whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(ArrayList(runningTasks)) + whenever(desktopWallpaperActivityTokenProvider.getToken()).thenReturn(wallpaperToken) + } + + private fun testDisplayWindowingModeSwitch( + defaultWindowingMode: Int, + extendedDisplayEnabled: Boolean, + expectTransition: Boolean, + ) { + defaultTDA.configuration.windowConfiguration.windowingMode = defaultWindowingMode + whenever(mockWindowManager.getWindowingMode(anyInt())).thenReturn(defaultWindowingMode) + val settingsSession = + ExtendedDisplaySettingsSession( + context.contentResolver, + if (extendedDisplayEnabled) 1 else 0, + ) + + settingsSession.use { + connectExternalDisplay() + defaultTDA.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM + disconnectExternalDisplay() + + if (expectTransition) { + val arg = argumentCaptor<WindowContainerTransaction>() + verify(transitions, times(2)) + .startTransition(eq(TRANSIT_CHANGE), arg.capture(), isNull()) + assertThat(arg.firstValue.changes[defaultTDA.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FREEFORM) + assertThat(arg.firstValue.changes[wallpaperToken.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) + assertThat(arg.secondValue.changes[defaultTDA.token.asBinder()]?.windowingMode) + .isEqualTo(defaultWindowingMode) + assertThat(arg.secondValue.changes[wallpaperToken.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) + } else { + verify(transitions, never()).startTransition(eq(TRANSIT_CHANGE), any(), isNull()) + } + } + } + + @Test + fun displayWindowingModeSwitchOnDisplayConnected_extendedDisplayDisabled() { + testDisplayWindowingModeSwitch( + defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, + extendedDisplayEnabled = false, + expectTransition = false, + ) + } + + @Test + fun displayWindowingModeSwitchOnDisplayConnected_fullscreenDisplay() { + testDisplayWindowingModeSwitch( + defaultWindowingMode = WINDOWING_MODE_FULLSCREEN, + extendedDisplayEnabled = true, + expectTransition = true, + ) + } + + @Test + fun displayWindowingModeSwitchOnDisplayConnected_freeformDisplay() { + testDisplayWindowingModeSwitch( + defaultWindowingMode = WINDOWING_MODE_FREEFORM, + extendedDisplayEnabled = true, + expectTransition = false, + ) + } + + @Test + fun displayWindowingModeSwitch_existingTasksOnConnected() { + defaultTDA.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN + whenever(mockWindowManager.getWindowingMode(anyInt())).thenReturn(WINDOWING_MODE_FULLSCREEN) + + ExtendedDisplaySettingsSession(context.contentResolver, 1).use { + connectExternalDisplay() + + val arg = argumentCaptor<WindowContainerTransaction>() + verify(transitions, times(1)) + .startTransition(eq(TRANSIT_CHANGE), arg.capture(), isNull()) + assertThat(arg.firstValue.changes[freeformTask.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_UNDEFINED) + assertThat(arg.firstValue.changes[fullscreenTask.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) + } + } + + @Test + fun displayWindowingModeSwitch_existingTasksOnDisconnected() { + defaultTDA.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM + whenever(mockWindowManager.getWindowingMode(anyInt())).thenAnswer { + WINDOWING_MODE_FULLSCREEN + } + + ExtendedDisplaySettingsSession(context.contentResolver, 1).use { + disconnectExternalDisplay() + + val arg = argumentCaptor<WindowContainerTransaction>() + verify(transitions, times(1)) + .startTransition(eq(TRANSIT_CHANGE), arg.capture(), isNull()) + assertThat(arg.firstValue.changes[freeformTask.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FREEFORM) + assertThat(arg.firstValue.changes[fullscreenTask.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_UNDEFINED) + } + } + + private fun connectExternalDisplay() { + whenever(rootTaskDisplayAreaOrganizer.getDisplayIds()) + .thenReturn(intArrayOf(DEFAULT_DISPLAY, EXTERNAL_DISPLAY_ID)) + controller.refreshDisplayWindowingMode() + } + + private fun disconnectExternalDisplay() { + whenever(rootTaskDisplayAreaOrganizer.getDisplayIds()) + .thenReturn(intArrayOf(DEFAULT_DISPLAY)) + controller.refreshDisplayWindowingMode() + } + + private class ExtendedDisplaySettingsSession( + private val contentResolver: ContentResolver, + private val overrideValue: Int, + ) : AutoCloseable { + private val settingName = DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS + private val initialValue = Settings.Global.getInt(contentResolver, settingName, 0) + + init { + Settings.Global.putInt(contentResolver, settingName, overrideValue) + } + + override fun close() { + Settings.Global.putInt(contentResolver, settingName, initialValue) + } + } + + private companion object { + const val EXTERNAL_DISPLAY_ID = 100 + } +} 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 e2c3dda0d927..fcd92ac2678a 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 @@ -285,7 +285,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() private val DEFAULT_PORTRAIT_BOUNDS = Rect(200, 165, 1400, 2085) private val RESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 435, 1575, 1635) private val RESIZABLE_PORTRAIT_BOUNDS = Rect(680, 75, 1880, 1275) - private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 449, 1575, 1611) + private val UNRESIZABLE_LANDSCAPE_BOUNDS = Rect(25, 448, 1575, 1611) private val UNRESIZABLE_PORTRAIT_BOUNDS = Rect(830, 75, 1730, 1275) private val wallpaperToken = MockToken().token() private val homeComponentName = ComponentName(HOME_LAUNCHER_PACKAGE_NAME, /* class */ "") @@ -2900,7 +2900,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test - @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP) + @EnableFlags( + FLAG_ENABLE_DESKTOP_WINDOWING_PIP, + Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, + ) fun onDesktopWindowClose_minimizedPipNotPresent_exitDesktop() { val freeformTask = setUpFreeformTask() val pipTask = setUpPipTask(autoEnterEnabled = true) @@ -2915,10 +2918,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val wct = WindowContainerTransaction() controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, freeformTask) - // Remove wallpaper operation - wct.hierarchyOps.any { hop -> - hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder() - } + // Moves wallpaper activity to back when leaving desktop + wct.assertReorder(wallpaperToken, toTop = false) } @Test @@ -3224,6 +3225,24 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test + fun onDesktopWindowMinimize_triesToStopTiling() { + val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY) + val transition = Binder() + whenever( + freeformTaskTransitionStarter.startMinimizedModeTransition( + any(), + anyInt(), + anyBoolean(), + ) + ) + .thenReturn(transition) + + controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON) + + verify(snapEventHandler).removeTaskIfTiled(eq(DEFAULT_DISPLAY), eq(task.taskId)) + } + + @Test fun handleRequest_fullscreenTask_freeformVisible_returnSwitchToFreeformWCT() { val homeTask = setUpHomeTask() val freeformTask = setUpFreeformTask() @@ -4338,7 +4357,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() } @Test - @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP) + @EnableFlags( + FLAG_ENABLE_DESKTOP_WINDOWING_PIP, + Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, + ) fun moveFocusedTaskToFullscreen_minimizedPipPresent_removeWallpaperActivity() { val freeformTask = setUpFreeformTask() val pipTask = setUpPipTask(autoEnterEnabled = true) @@ -4356,10 +4378,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase() val taskChange = assertNotNull(wct.changes[freeformTask.token.asBinder()]) assertThat(taskChange.windowingMode) .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN - // Remove wallpaper operation - wct.hierarchyOps.any { hop -> - hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK && hop.container == wallpaperToken.asBinder() - } + // Moves wallpaper activity to back when leaving desktop + wct.assertReorder(wallpaperToken, toTop = false) } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt index c29edece5537..dd577f402952 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt @@ -24,6 +24,7 @@ import android.content.Context import android.content.Intent import android.os.Binder import android.os.IBinder +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.Display.DEFAULT_DISPLAY import android.view.WindowManager @@ -168,7 +169,8 @@ class DesktopTasksTransitionObserverTest { @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) - fun backNavigation_withCloseTransitionLastTask_taskMinimized() { + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER) + fun backNavigation_withCloseTransitionLastTask_wallpaperActivityClosed_taskMinimized() { val task = createTaskInfo(1) val transition = mock<IBinder>() whenever(taskRepository.getVisibleTaskCount(any())).thenReturn(1) @@ -193,6 +195,35 @@ class DesktopTasksTransitionObserverTest { } @Test + @EnableFlags( + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION, + Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER, + ) + fun backNavigation_withCloseTransitionLastTask_wallpaperActivityReordered_taskMinimized() { + val task = createTaskInfo(1) + val transition = mock<IBinder>() + whenever(taskRepository.getVisibleTaskCount(any())).thenReturn(1) + whenever(taskRepository.isClosingTask(task.taskId)).thenReturn(false) + whenever(backAnimationController.latestTriggerBackTask).thenReturn(task.taskId) + + transitionObserver.onTransitionReady( + transition = transition, + info = createBackNavigationTransition(task, TRANSIT_CLOSE, true, TRANSIT_TO_BACK), + startTransaction = mock(), + finishTransaction = mock(), + ) + + verify(taskRepository).minimizeTask(task.displayId, task.taskId) + val pendingTransition = + DesktopMixedTransitionHandler.PendingMixedTransition.Minimize( + transition, + task.taskId, + isLastTask = true, + ) + verify(mixedHandler).addPendingMixedTransition(pendingTransition) + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) fun backNavigation_nullTaskInfo_taskNotMinimized() { val task = createTaskInfo(1) @@ -434,6 +465,7 @@ class DesktopTasksTransitionObserverTest { task: RunningTaskInfo?, type: Int = TRANSIT_TO_BACK, withWallpaper: Boolean = false, + wallpaperChangeMode: Int = TRANSIT_CLOSE, ): TransitionInfo { return TransitionInfo(type, /* flags= */ 0).apply { addChange( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProviderTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProviderTest.kt new file mode 100644 index 000000000000..aa4e9aaf248e --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProviderTest.kt @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.desktopmode.desktopwallpaperactivity + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.Display.DEFAULT_DISPLAY +import androidx.test.filters.SmallTest +import com.android.wm.shell.MockToken +import com.android.wm.shell.ShellTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Test class for [DesktopWallpaperActivityTokenProvider] + * + * Usage: atest WMShellUnitTests:DesktopWallpaperActivityTokenProviderTest + */ +@SmallTest +@RunWithLooper +@RunWith(AndroidTestingRunner::class) +class DesktopWallpaperActivityTokenProviderTest : ShellTestCase() { + + private lateinit var provider: DesktopWallpaperActivityTokenProvider + private val DEFAULT_DISPLAY = 0 + private val SECONDARY_DISPLAY = 1 + + @Before + fun setUp() { + provider = DesktopWallpaperActivityTokenProvider() + } + + @Test + fun setToken_setsTokenForDisplay() { + val token = MockToken().token() + + provider.setToken(token, DEFAULT_DISPLAY) + + assertThat(provider.getToken(DEFAULT_DISPLAY)).isEqualTo(token) + } + + @Test + fun setToken_overwritesExistingTokenForDisplay() { + val token1 = MockToken().token() + val token2 = MockToken().token() + + provider.setToken(token1, DEFAULT_DISPLAY) + provider.setToken(token2, DEFAULT_DISPLAY) + + assertThat(provider.getToken(DEFAULT_DISPLAY)).isEqualTo(token2) + } + + @Test + fun getToken_returnsNullForNonExistentDisplay() { + assertThat(provider.getToken(SECONDARY_DISPLAY)).isNull() + } + + @Test + fun removeToken_removesTokenForDisplay() { + val token = MockToken().token() + + provider.setToken(token, DEFAULT_DISPLAY) + provider.removeToken(DEFAULT_DISPLAY) + + assertThat(provider.getToken(DEFAULT_DISPLAY)).isNull() + } + + @Test + fun removeToken_withToken_removesTokenForDisplay() { + val token = MockToken().token() + + provider.setToken(token, DEFAULT_DISPLAY) + provider.removeToken(token) + + assertThat(provider.getToken(DEFAULT_DISPLAY)).isNull() + } + + @Test + fun removeToken_doesNothingForNonExistentDisplay() { + provider.removeToken(SECONDARY_DISPLAY) + + assertThat(provider.getToken(SECONDARY_DISPLAY)).isNull() + } + + @Test + fun removeToken_withNonExistentToken_doesNothing() { + val token1 = MockToken().token() + val token2 = MockToken().token() + + provider.setToken(token1, DEFAULT_DISPLAY) + provider.removeToken(token2) + + assertThat(provider.getToken(DEFAULT_DISPLAY)).isEqualTo(token1) + } + + @Test + fun multipleDisplays_tokensAreIndependent() { + val token1 = MockToken().token() + val token2 = MockToken().token() + + provider.setToken(token1, DEFAULT_DISPLAY) + provider.setToken(token2, SECONDARY_DISPLAY) + + assertThat(provider.getToken(DEFAULT_DISPLAY)).isEqualTo(token1) + assertThat(provider.getToken(SECONDARY_DISPLAY)).isEqualTo(token2) + + provider.removeToken(DEFAULT_DISPLAY) + + assertThat(provider.getToken(DEFAULT_DISPLAY)).isNull() + assertThat(provider.getToken(SECONDARY_DISPLAY)).isEqualTo(token2) + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTouchStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTouchStateTest.java new file mode 100644 index 000000000000..2e389b7dd151 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTouchStateTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.pip2.phone; + +import static android.view.MotionEvent.ACTION_BUTTON_PRESS; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_MOVE; +import static android.view.MotionEvent.ACTION_UP; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.os.SystemClock; +import android.testing.AndroidTestingRunner; +import android.view.MotionEvent; +import android.view.ViewConfiguration; + +import androidx.test.filters.SmallTest; + +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.TestShellExecutor; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.CountDownLatch; + +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class PipTouchStateTest extends ShellTestCase { + + private PipTouchState mTouchState; + private CountDownLatch mDoubleTapCallbackTriggeredLatch; + private CountDownLatch mHoverExitCallbackTriggeredLatch; + private TestShellExecutor mMainExecutor; + + @Before + public void setUp() throws Exception { + mMainExecutor = new TestShellExecutor(); + mDoubleTapCallbackTriggeredLatch = new CountDownLatch(1); + mHoverExitCallbackTriggeredLatch = new CountDownLatch(1); + mTouchState = new PipTouchState(ViewConfiguration.get(getContext()), + mDoubleTapCallbackTriggeredLatch::countDown, + mHoverExitCallbackTriggeredLatch::countDown, + mMainExecutor); + assertFalse(mTouchState.isDoubleTap()); + assertFalse(mTouchState.isWaitingForDoubleTap()); + } + + @Test + public void testDoubleTapLongSingleTap_notDoubleTapAndNotWaiting() { + final long currentTime = SystemClock.uptimeMillis(); + + mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, currentTime, 0, 0)); + mTouchState.onTouchEvent(createMotionEvent(ACTION_UP, + currentTime + PipTouchState.DOUBLE_TAP_TIMEOUT + 10, 0, 0)); + assertFalse(mTouchState.isDoubleTap()); + assertFalse(mTouchState.isWaitingForDoubleTap()); + assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == -1); + } + + @Test + public void testDoubleTapTimeout_timeoutCallbackCalled() throws Exception { + final long currentTime = SystemClock.uptimeMillis(); + + mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, currentTime, 0, 0)); + mTouchState.onTouchEvent(createMotionEvent(ACTION_UP, + currentTime + PipTouchState.DOUBLE_TAP_TIMEOUT - 10, 0, 0)); + assertFalse(mTouchState.isDoubleTap()); + assertTrue(mTouchState.isWaitingForDoubleTap()); + + assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == 10); + mTouchState.scheduleDoubleTapTimeoutCallback(); + + mMainExecutor.flushAll(); + assertTrue(mDoubleTapCallbackTriggeredLatch.getCount() == 0); + } + + @Test + public void testDoubleTapDrag_doubleTapCanceled() { + final long currentTime = SystemClock.uptimeMillis(); + + mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, currentTime, 0, 0)); + mTouchState.onTouchEvent(createMotionEvent(ACTION_MOVE, currentTime + 10, 500, 500)); + mTouchState.onTouchEvent(createMotionEvent(ACTION_UP, currentTime + 20, 500, 500)); + assertTrue(mTouchState.isDragging()); + assertFalse(mTouchState.isDoubleTap()); + assertFalse(mTouchState.isWaitingForDoubleTap()); + assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == -1); + } + + @Test + public void testDoubleTap_doubleTapRegistered() { + final long currentTime = SystemClock.uptimeMillis(); + + mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, currentTime, 0, 0)); + mTouchState.onTouchEvent(createMotionEvent(ACTION_UP, currentTime + 10, 0, 0)); + mTouchState.onTouchEvent(createMotionEvent(ACTION_DOWN, + currentTime + PipTouchState.DOUBLE_TAP_TIMEOUT - 20, 0, 0)); + mTouchState.onTouchEvent(createMotionEvent(ACTION_UP, + currentTime + PipTouchState.DOUBLE_TAP_TIMEOUT - 10, 0, 0)); + assertTrue(mTouchState.isDoubleTap()); + assertFalse(mTouchState.isWaitingForDoubleTap()); + assertTrue(mTouchState.getDoubleTapTimeoutCallbackDelay() == -1); + } + + @Test + public void testHoverExitTimeout_timeoutCallbackCalled() throws Exception { + mTouchState.scheduleHoverExitTimeoutCallback(); + mMainExecutor.flushAll(); + assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 0); + } + + @Test + public void testHoverExitTimeout_timeoutCallbackNotCalled() throws Exception { + mTouchState.scheduleHoverExitTimeoutCallback(); + assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 1); + } + + @Test + public void testHoverExitTimeout_timeoutCallbackNotCalled_ifButtonPress() throws Exception { + mTouchState.scheduleHoverExitTimeoutCallback(); + mTouchState.onTouchEvent(createMotionEvent(ACTION_BUTTON_PRESS, SystemClock.uptimeMillis(), + 0, 0)); + mMainExecutor.flushAll(); + assertTrue(mHoverExitCallbackTriggeredLatch.getCount() == 1); + } + + private MotionEvent createMotionEvent(int action, long eventTime, float x, float y) { + return MotionEvent.obtain(0, eventTime, action, x, y, 0); + } + +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java index 5028479b6ace..a546b3ea7d8f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java @@ -107,6 +107,7 @@ import java.util.function.Consumer; @RunWith(AndroidJUnit4.class) @SmallTest public class RecentTasksControllerTest extends ShellTestCase { + private static final String SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"; @Mock private Context mContext; @@ -582,6 +583,19 @@ public class RecentTasksControllerTest extends ShellTestCase { @Test @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS}) + public void onTaskAdded_orDesktopWallpaperActivity_doesNotTriggerOnRunningTaskAppeared() + throws Exception { + RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10); + mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener); + + mRecentTasksControllerReal.onTaskAdded(taskInfo); + + verify(mRecentTasksListener, never()).onRunningTaskAppeared(any()); + } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS}) public void taskWindowingModeChanged_desktopRunningAppsEnabled_triggersOnRunningTaskChanged() throws Exception { mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener); @@ -593,6 +607,19 @@ public class RecentTasksControllerTest extends ShellTestCase { } @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS}) + public void taskInfoChanged_forDesktopWallpaperActivity_doesNotTriggerOnRunningTaskChanged() + throws Exception { + RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10); + mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener); + + mRecentTasksControllerReal.onTaskRunningInfoChanged(taskInfo); + + verify(mRecentTasksListener, never()).onRunningTaskChanged(any()); + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS) public void @@ -619,6 +646,20 @@ public class RecentTasksControllerTest extends ShellTestCase { verify(mRecentTasksListener).onRunningTaskVanished(taskInfo); } + + @Test + @EnableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, + Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS}) + public void onTaskRemoved_forDesktopWallpaperActivity_doesNotTriggerOnRunningTaskVanished() + throws Exception { + RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10); + mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener); + + mRecentTasksControllerReal.onTaskRemoved(taskInfo); + + verify(mRecentTasksListener, never()).onRunningTaskVanished(any()); + } + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS) @@ -659,6 +700,18 @@ public class RecentTasksControllerTest extends ShellTestCase { } @Test + @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + public void onDesktopWallpaperActivityMovedToFront_doesNotTriggerOnTaskMovedToFront() + throws Exception { + RunningTaskInfo taskInfo = makeDesktopWallpaperActivityTaskInfo(/* taskId= */10); + mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener); + + mRecentTasksControllerReal.onTaskMovedToFrontThroughTransition(taskInfo); + + verify(mRecentTasksListener, never()).onTaskMovedToFront(any()); + } + + @Test public void getNullSplitBoundsNonSplitTask() { SplitBounds sb = mRecentTasksController.getSplitBoundsForTaskId(3); assertNull("splitBounds should be null for non-split task", sb); @@ -829,16 +882,25 @@ public class RecentTasksControllerTest extends ShellTestCase { * Helper to create a running task with a given task id. */ private RunningTaskInfo makeRunningTaskInfo(int taskId) { + return makeRunningTaskInfo(taskId, new ComponentName("com." + taskId, "Activity" + taskId)); + } + + private RunningTaskInfo makeRunningTaskInfo(int taskId, ComponentName intentComponent) { RunningTaskInfo info = new RunningTaskInfo(); info.taskId = taskId; info.realActivity = new ComponentName("testPackage", "testClass"); Intent intent = new Intent(); - intent.setComponent(new ComponentName("com." + taskId, "Activity" + taskId)); + intent.setComponent(intentComponent); info.baseIntent = intent; info.lastNonFullscreenBounds = new Rect(); return info; } + private RunningTaskInfo makeDesktopWallpaperActivityTaskInfo(int taskId) { + return makeRunningTaskInfo(taskId, new ComponentName(SYSTEM_UI_PACKAGE_NAME, + DesktopWallpaperActivity.class.getName())); + } + /** * Helper to set the raw task list on the controller. */ diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt index efb91c5fbfda..180a6915b45f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt @@ -16,23 +16,33 @@ package com.android.wm.shell.shared.bubbles +import android.content.Context import android.graphics.Rect +import android.view.View +import android.widget.FrameLayout +import androidx.core.animation.AnimatorTestRule +import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry import com.google.common.truth.Truth.assertThat +import kotlin.test.assertFails import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import kotlin.test.assertFails /** Unit tests for [DropTargetManager]. */ @SmallTest @RunWith(AndroidJUnit4::class) class DropTargetManagerTest { + @get:Rule val animatorTestRule = AnimatorTestRule() + + private val context = getApplicationContext<Context>() private lateinit var dropTargetManager: DropTargetManager private lateinit var dragZoneChangedListener: FakeDragZoneChangedListener - private val dropTarget = Rect(0, 0, 0, 0) + private lateinit var container: FrameLayout // create 3 drop zones that are horizontally next to each other // ------------------------------------------------- @@ -43,15 +53,20 @@ class DropTargetManagerTest { // | | | | // ------------------------------------------------- private val bubbleLeftDragZone = - DragZone.Bubble.Left(bounds = Rect(0, 0, 100, 100), dropTarget = dropTarget) + DragZone.Bubble.Left(bounds = Rect(0, 0, 100, 100), dropTarget = Rect(0, 0, 50, 200)) private val dismissDragZone = DragZone.Dismiss(bounds = Rect(100, 0, 200, 100)) private val bubbleRightDragZone = - DragZone.Bubble.Right(bounds = Rect(200, 0, 300, 100), dropTarget = dropTarget) + DragZone.Bubble.Right(bounds = Rect(200, 0, 300, 100), dropTarget = Rect(200, 0, 280, 150)) + + private val dropTargetView: View + get() = container.getChildAt(0) @Before fun setUp() { + container = FrameLayout(context) dragZoneChangedListener = FakeDragZoneChangedListener() - dropTargetManager = DropTargetManager(isLayoutRtl = false, dragZoneChangedListener) + dropTargetManager = + DropTargetManager(context, container, isLayoutRtl = false, dragZoneChangedListener) } @Test @@ -79,17 +94,21 @@ class DropTargetManagerTest { DraggedObject.Bubble(BubbleBarLocation.LEFT), listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone) ) - dropTargetManager.onDragUpdated( - bubbleRightDragZone.bounds.centerX(), - bubbleRightDragZone.bounds.centerY() - ) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated( + bubbleRightDragZone.bounds.centerX(), + bubbleRightDragZone.bounds.centerY() + ) + } assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleLeftDragZone) assertThat(dragZoneChangedListener.toDragZone).isEqualTo(bubbleRightDragZone) - dropTargetManager.onDragUpdated( - dismissDragZone.bounds.centerX(), - dismissDragZone.bounds.centerY() - ) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated( + dismissDragZone.bounds.centerX(), + dismissDragZone.bounds.centerY() + ) + } assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleRightDragZone) assertThat(dragZoneChangedListener.toDragZone).isEqualTo(dismissDragZone) } @@ -100,10 +119,12 @@ class DropTargetManagerTest { DraggedObject.Bubble(BubbleBarLocation.LEFT), listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone) ) - dropTargetManager.onDragUpdated( - bubbleLeftDragZone.bounds.centerX(), - bubbleLeftDragZone.bounds.centerY() - ) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated( + bubbleLeftDragZone.bounds.centerX(), + bubbleLeftDragZone.bounds.centerY() + ) + } assertThat(dragZoneChangedListener.fromDragZone).isNull() assertThat(dragZoneChangedListener.toDragZone).isNull() } @@ -118,7 +139,9 @@ class DropTargetManagerTest { val pointY = 200 assertThat(bubbleLeftDragZone.contains(pointX, pointY)).isFalse() assertThat(bubbleRightDragZone.contains(pointX, pointY)).isFalse() - dropTargetManager.onDragUpdated(pointX, pointY) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated(pointX, pointY) + } assertThat(dragZoneChangedListener.fromDragZone).isNull() assertThat(dragZoneChangedListener.toDragZone).isNull() } @@ -135,27 +158,30 @@ class DropTargetManagerTest { // drag to a point that is within both the bubble right zone and split zone val (pointX, pointY) = - Pair( - bubbleRightDragZone.bounds.centerX(), - bubbleRightDragZone.bounds.centerY() - ) + Pair(bubbleRightDragZone.bounds.centerX(), bubbleRightDragZone.bounds.centerY()) assertThat(splitDragZone.contains(pointX, pointY)).isTrue() - dropTargetManager.onDragUpdated(pointX, pointY) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated(pointX, pointY) + } // verify we dragged to the bubble right zone because that has higher priority than split assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleLeftDragZone) assertThat(dragZoneChangedListener.toDragZone).isEqualTo(bubbleRightDragZone) - dropTargetManager.onDragUpdated( - bubbleRightDragZone.bounds.centerX(), - 150 // below the bubble and dismiss drag zones but within split - ) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated( + bubbleRightDragZone.bounds.centerX(), + 150 // below the bubble and dismiss drag zones but within split + ) + } assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(bubbleRightDragZone) assertThat(dragZoneChangedListener.toDragZone).isEqualTo(splitDragZone) val (dismissPointX, dismissPointY) = Pair(dismissDragZone.bounds.centerX(), dismissDragZone.bounds.centerY()) assertThat(splitDragZone.contains(dismissPointX, dismissPointY)).isTrue() - dropTargetManager.onDragUpdated(dismissPointX, dismissPointY) + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated(dismissPointX, dismissPointY) + } assertThat(dragZoneChangedListener.fromDragZone).isEqualTo(splitDragZone) assertThat(dragZoneChangedListener.toDragZone).isEqualTo(dismissDragZone) } @@ -166,7 +192,9 @@ class DropTargetManagerTest { DraggedObject.Bubble(BubbleBarLocation.LEFT), listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone) ) - dropTargetManager.onDragEnded() + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragEnded() + } dropTargetManager.onDragUpdated( bubbleRightDragZone.bounds.centerX(), bubbleRightDragZone.bounds.centerY() @@ -175,6 +203,129 @@ class DropTargetManagerTest { assertThat(dragZoneChangedListener.toDragZone).isNull() } + @Test + fun onDragStarted_dropTargetAddedToContainer() { + dropTargetManager.onDragStarted( + DraggedObject.Bubble(BubbleBarLocation.LEFT), + listOf(bubbleLeftDragZone, bubbleRightDragZone) + ) + assertThat(container.childCount).isEqualTo(1) + assertThat(dropTargetView.alpha).isEqualTo(0) + } + + @Test + fun onDragEnded_dropTargetRemovedFromContainer() { + dropTargetManager.onDragStarted( + DraggedObject.Bubble(BubbleBarLocation.LEFT), + listOf(bubbleLeftDragZone, bubbleRightDragZone) + ) + assertThat(container.childCount).isEqualTo(1) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragEnded() + animatorTestRule.advanceTimeBy(250) + } + assertThat(container.childCount).isEqualTo(0) + } + + @Test + fun startNewDrag_beforeDropTargetRemoved() { + dropTargetManager.onDragStarted( + DraggedObject.Bubble(BubbleBarLocation.LEFT), + listOf(bubbleLeftDragZone, bubbleRightDragZone) + ) + assertThat(container.childCount).isEqualTo(1) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragEnded() + // advance the timer by 100ms so the animation doesn't complete + animatorTestRule.advanceTimeBy(100) + } + assertThat(container.childCount).isEqualTo(1) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragStarted( + DraggedObject.Bubble(BubbleBarLocation.LEFT), + listOf(bubbleLeftDragZone, bubbleRightDragZone) + ) + } + assertThat(container.childCount).isEqualTo(1) + } + + @Test + fun updateDragZone_withDropTarget_dropTargetUpdated() { + dropTargetManager.onDragStarted( + DraggedObject.Bubble(BubbleBarLocation.LEFT), + listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone) + ) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated( + bubbleRightDragZone.bounds.centerX(), + bubbleRightDragZone.bounds.centerY() + ) + animatorTestRule.advanceTimeBy(250) + } + + assertThat(dropTargetView.alpha).isEqualTo(1) + verifyDropTargetPosition(bubbleRightDragZone.dropTarget) + } + + @Test + fun updateDragZone_withoutDropTarget_dropTargetHidden() { + dropTargetManager.onDragStarted( + DraggedObject.Bubble(BubbleBarLocation.LEFT), + listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone) + ) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated( + dismissDragZone.bounds.centerX(), + dismissDragZone.bounds.centerY() + ) + animatorTestRule.advanceTimeBy(250) + } + + assertThat(dropTargetView.alpha).isEqualTo(0) + } + + @Test + fun updateDragZone_betweenZonesWithDropTarget_dropTargetUpdated() { + dropTargetManager.onDragStarted( + DraggedObject.Bubble(BubbleBarLocation.LEFT), + listOf(dismissDragZone, bubbleLeftDragZone, bubbleRightDragZone) + ) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated( + bubbleRightDragZone.bounds.centerX(), + bubbleRightDragZone.bounds.centerY() + ) + animatorTestRule.advanceTimeBy(250) + } + + assertThat(dropTargetView.alpha).isEqualTo(1) + verifyDropTargetPosition(bubbleRightDragZone.dropTarget) + + InstrumentationRegistry.getInstrumentation().runOnMainSync { + dropTargetManager.onDragUpdated( + bubbleLeftDragZone.bounds.centerX(), + bubbleLeftDragZone.bounds.centerY() + ) + animatorTestRule.advanceTimeBy(250) + } + + assertThat(dropTargetView.alpha).isEqualTo(1) + verifyDropTargetPosition(bubbleLeftDragZone.dropTarget) + } + + private fun verifyDropTargetPosition(rect: Rect) { + assertThat(dropTargetView.scaleX).isEqualTo(rect.width()) + assertThat(dropTargetView.scaleY).isEqualTo(rect.height()) + assertThat(dropTargetView.translationX).isEqualTo(rect.exactCenterX()) + assertThat(dropTargetView.translationY).isEqualTo(rect.exactCenterY()) + } + private class FakeDragZoneChangedListener : DropTargetManager.DragZoneChangedListener { var initialDragZone: DragZone? = null var fromDragZone: DragZone? = null @@ -183,6 +334,7 @@ class DropTargetManagerTest { override fun onInitialDragZoneSet(dragZone: DragZone) { initialDragZone = dragZone } + override fun onDragZoneChanged(from: DragZone, to: DragZone) { fromDragZone = from toDragZone = to diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicyTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicyTest.kt index f69bf34ea3f7..88c6e499b869 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicyTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeCompatPolicyTest.kt @@ -16,13 +16,16 @@ package com.android.wm.shell.shared.desktopmode +import android.Manifest.permission.SYSTEM_ALERT_WINDOW import android.app.TaskInfo import android.compat.testing.PlatformCompatChangeRule import android.content.ComponentName import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.os.Process +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest @@ -39,7 +42,9 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyString import org.mockito.kotlin.any +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @@ -55,6 +60,7 @@ class DesktopModeCompatPolicyTest : ShellTestCase() { private lateinit var desktopModeCompatPolicy: DesktopModeCompatPolicy private val packageManager: PackageManager = mock() private val homeActivities = ComponentName(HOME_LAUNCHER_PACKAGE_NAME, /* class */ "") + private val baseActivityTest = ComponentName("com.test.dummypackage", "TestClass") @Before fun setUp() { @@ -64,6 +70,7 @@ class DesktopModeCompatPolicyTest : ShellTestCase() { } @Test + @DisableFlags(Flags.FLAG_ENABLE_MODALS_FULLSCREEN_WITH_PERMISSION) fun testIsTopActivityExemptFromDesktopWindowing_onlyTransparentActivitiesInStack() { assertTrue(desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing( createFreeformTask(/* displayId */ 0) @@ -71,10 +78,39 @@ class DesktopModeCompatPolicyTest : ShellTestCase() { isActivityStackTransparent = true isTopActivityNoDisplay = false numActivities = 1 + baseActivity = baseActivityTest })) } @Test + @EnableFlags(Flags.FLAG_ENABLE_MODALS_FULLSCREEN_WITH_PERMISSION) + fun testIsTopActivityExemptWithPermission_onlyTransparentActivitiesInStack() { + allowOverlayPermission(arrayOf(SYSTEM_ALERT_WINDOW)) + assertTrue(desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing( + createFreeformTask(/* displayId */ 0) + .apply { + isActivityStackTransparent = true + isTopActivityNoDisplay = false + numActivities = 1 + baseActivity = baseActivityTest + })) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_MODALS_FULLSCREEN_WITH_PERMISSION) + fun testIsTopActivityExemptWithNoPermission_onlyTransparentActivitiesInStack() { + allowOverlayPermission(arrayOf()) + assertFalse(desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing( + createFreeformTask(/* displayId */ 0) + .apply { + isActivityStackTransparent = true + isTopActivityNoDisplay = false + numActivities = 1 + baseActivity = baseActivityTest + })) + } + + @Test fun testIsTopActivityExemptFromDesktopWindowing_noActivitiesInStack() { assertFalse(desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing( createFreeformTask(/* displayId */ 0) @@ -219,4 +255,15 @@ class DesktopModeCompatPolicyTest : ShellTestCase() { } } } + + fun allowOverlayPermission(permissions: Array<String>) { + val packageInfo = mock<PackageInfo>() + packageInfo.requestedPermissions = permissions + whenever( + packageManager.getPackageInfo( + anyString(), + eq(PackageManager.GET_PERMISSIONS) + ) + ).thenReturn(packageInfo) + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt index 741a0fdcf63c..4082ffd4ac0a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt @@ -22,8 +22,6 @@ import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.annotations.Presubmit import android.platform.test.flag.junit.SetFlagsRule -import android.provider.Settings -import android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES import android.window.DesktopModeFlags import androidx.test.filters.SmallTest import com.android.internal.R @@ -63,14 +61,12 @@ class DesktopModeStatusTest : ShellTestCase() { doReturn(context.contentResolver).whenever(mockContext).contentResolver resetDesktopModeFlagsCache() resetEnforceDeviceRestriction() - resetFlagOverride() } @After fun tearDown() { resetDesktopModeFlagsCache() resetEnforceDeviceRestriction() - resetFlagOverride() } @DisableFlags( @@ -246,18 +242,11 @@ class DesktopModeStatusTest : ShellTestCase() { cachedToggleOverride.set(null, null) } - private fun resetFlagOverride() { - Settings.Global.putString( - context.contentResolver, - DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null - ) - } - private fun setFlagOverride(override: DesktopModeFlags.ToggleOverride) { - Settings.Global.putInt( - context.contentResolver, - DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, override.setting - ) + val cachedToggleOverride = + DesktopModeFlags::class.java.getDeclaredField("sCachedToggleOverride") + cachedToggleOverride.isAccessible = true + cachedToggleOverride.set(null, override) } private fun setDeviceEligibleForDesktopMode(eligible: Boolean) { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt index 8cccdb2b6120..81dfaed56b6f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt @@ -52,6 +52,7 @@ import com.android.wm.shell.common.DisplayChangeController import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayInsetsController import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.desktopmode.DesktopActivityOrientationChangeHandler @@ -138,6 +139,8 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { protected val mockFreeformTaskTransitionStarter = mock<FreeformTaskTransitionStarter>() protected val mockActivityOrientationChangeHandler = mock<DesktopActivityOrientationChangeHandler>() + protected val mockMultiDisplayDragMoveIndicatorController = + mock<MultiDisplayDragMoveIndicatorController>() protected val mockInputManager = mock<InputManager>() private val mockTaskPositionerFactory = mock<DesktopModeWindowDecorViewModel.TaskPositionerFactory>() @@ -229,6 +232,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { mockRecentsTransitionHandler, desktopModeCompatPolicy, mockTilingWindowDecoration, + mockMultiDisplayDragMoveIndicatorController, ) desktopModeWindowDecorViewModel.setSplitScreenController(mockSplitScreenController) whenever(mockDisplayController.getDisplayLayout(any())).thenReturn(mockDisplayLayout) @@ -243,6 +247,7 @@ open class DesktopModeWindowDecorViewModelTestsBase : ShellTestCase() { any(), any(), any(), + any(), any() ) ) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt new file mode 100644 index 000000000000..7341e098add5 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragResizeInputListenerTest.kt @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.windowdecor + +import android.app.ActivityManager +import android.content.Context +import android.graphics.Region +import android.os.Handler +import android.os.Looper +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.util.Size +import android.view.Choreographer +import android.view.Display +import android.view.IWindowSession +import android.view.InputChannel +import android.view.SurfaceControl +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestHandler +import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.common.DisplayController +import com.android.wm.shell.desktopmode.DesktopModeEventLogger +import com.android.wm.shell.util.StubTransaction +import com.android.wm.shell.windowdecor.DragResizeInputListener.TaskResizeInputEventReceiver +import com.google.common.truth.Truth.assertThat +import java.util.function.Consumer +import java.util.function.Supplier +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify + +/** + * Tests for [DragResizeInputListener]. + * + * Build/Install/Run: + * atest WMShellUnitTests:DragResizeInputListenerTest + */ +@SmallTest +@TestableLooper.RunWithLooper +@RunWith(AndroidTestingRunner::class) +class DragResizeInputListenerTest : ShellTestCase() { + private val testMainExecutor = TestShellExecutor() + private val testBgExecutor = TestShellExecutor() + private val mockWindowSession = mock<IWindowSession>() + private val mockInputEventReceiver = mock<TaskResizeInputEventReceiver>() + + @Test + fun testGrantInputChannelOffMainThread() { + create() + testMainExecutor.flushAll() + + verifyNoInputChannelGrantRequests() + } + + @Test + fun testInitializationCallback_waitsForBgSetup() { + val inputListener = create() + + val callback = TestInitializationCallback() + inputListener.addInitializedCallback(callback) + assertThat(callback.initialized).isFalse() + + testBgExecutor.flushAll() + testMainExecutor.flushAll() + + assertThat(callback.initialized).isTrue() + } + + @Test + fun testInitializationCallback_alreadyInitialized_callsBackImmediately() { + val inputListener = create() + testBgExecutor.flushAll() + testMainExecutor.flushAll() + + val callback = TestInitializationCallback() + inputListener.addInitializedCallback(callback) + + assertThat(callback.initialized).isTrue() + } + + @Test + fun testClose_beforeBgSetup_cancelsBgSetup() { + val inputListener = create() + + inputListener.close() + testBgExecutor.flushAll() + + verifyNoInputChannelGrantRequests() + } + + @Test + fun testClose_beforeBgSetupResultSet_cancelsInit() { + val inputListener = create() + val callback = TestInitializationCallback() + inputListener.addInitializedCallback(callback) + + testBgExecutor.flushAll() + inputListener.close() + testMainExecutor.flushAll() + + assertThat(callback.initialized).isFalse() + } + + @Test + fun testClose_afterInit_disposesOfReceiver() { + val inputListener = create() + + testBgExecutor.flushAll() + testMainExecutor.flushAll() + inputListener.close() + + verify(mockInputEventReceiver).dispose() + } + + @Test + fun testClose_afterInit_removesTokens() { + val inputListener = create() + + inputListener.close() + testBgExecutor.flushAll() + + verify(mockWindowSession).remove(inputListener.mClientToken) + verify(mockWindowSession).remove(inputListener.mSinkClientToken) + } + + private fun verifyNoInputChannelGrantRequests() { + verify(mockWindowSession, never()) + .grantInputChannel( + anyInt(), + any(), + any(), + anyOrNull(), + anyInt(), + anyInt(), + anyInt(), + anyInt(), + anyOrNull(), + any(), + any(), + any(), + ) + } + + private fun create(): DragResizeInputListener = + DragResizeInputListener( + context, + mockWindowSession, + testMainExecutor, + testBgExecutor, + TestTaskResizeInputEventReceiverFactory(mockInputEventReceiver), + TestRunningTaskInfoBuilder().build(), + TestHandler(Looper.getMainLooper()), + mock<Choreographer>(), + Display.DEFAULT_DISPLAY, + mock<SurfaceControl>(), + mock<DragPositioningCallback>(), + { SurfaceControl.Builder() }, + { StubTransaction() }, + mock<DisplayController>(), + mock<DesktopModeEventLogger>(), + ) + + private class TestInitializationCallback : Runnable { + var initialized: Boolean = false + private set + + override fun run() { + initialized = true + } + } + + private class TestTaskResizeInputEventReceiverFactory( + private val mockInputEventReceiver: TaskResizeInputEventReceiver + ) : DragResizeInputListener.TaskResizeInputEventReceiverFactory { + override fun create( + context: Context, + taskInfo: ActivityManager.RunningTaskInfo, + inputChannel: InputChannel, + callback: DragPositioningCallback, + handler: Handler, + choreographer: Choreographer, + displayLayoutSizeSupplier: Supplier<Size?>, + touchRegionConsumer: Consumer<Region?>, + desktopModeEventLogger: DesktopModeEventLogger, + ): TaskResizeInputEventReceiver = mockInputEventReceiver + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt index 937938df82c8..a6b077037b86 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/MultiDisplayVeiledResizeTaskPositionerTest.kt @@ -41,6 +41,7 @@ import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.MultiDisplayDragMoveIndicatorController import com.android.wm.shell.common.MultiDisplayTestUtil import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TransitionFinishCallback @@ -62,8 +63,8 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever import org.mockito.Mockito.`when` +import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations /** @@ -93,7 +94,8 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() { @Mock private lateinit var mockTransitions: Transitions @Mock private lateinit var mockInteractionJankMonitor: InteractionJankMonitor @Mock private lateinit var mockSurfaceControl: SurfaceControl - + @Mock private lateinit var mockMultiDisplayDragMoveIndicatorController: + MultiDisplayDragMoveIndicatorController private lateinit var resources: TestableResources private lateinit var spyDisplayLayout0: DisplayLayout private lateinit var spyDisplayLayout1: DisplayLayout @@ -170,10 +172,11 @@ class MultiDisplayVeiledResizeTaskPositionerTest : ShellTestCase() { mockDesktopWindowDecoration, mockDisplayController, mockDragEventListener, - mockTransactionFactory, + { mockTransaction }, mockTransitions, mockInteractionJankMonitor, mainHandler, + mockMultiDisplayDragMoveIndicatorController, ) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt index d99a4825e580..c86730ed1dc7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt @@ -20,6 +20,7 @@ import android.testing.TestableLooper import android.view.SurfaceControl import android.view.View import android.view.WindowManager +import android.widget.FrameLayout import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase import com.google.common.truth.Truth.assertThat @@ -30,6 +31,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock +import org.mockito.Mockito.times +import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.never import org.mockito.kotlin.spy import org.mockito.kotlin.verify @@ -47,24 +51,46 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() { fun update_differentView_replacesView() = runTest { val view = View(context) val lp = WindowManager.LayoutParams() - val reusableVH = createReusableViewHost() - reusableVH.updateView(view, lp, context.resources.configuration, null) + val rootView = FrameLayout(context) + val reusableVH = createReusableViewHost(rootView) + reusableVH.updateView(view, lp, context.resources.configuration) - assertThat(reusableVH.rootView.childCount).isEqualTo(1) - assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(view) + assertThat(rootView.childCount).isEqualTo(1) + assertThat(rootView.getChildAt(0)).isEqualTo(view) val newView = View(context) val newLp = WindowManager.LayoutParams() - reusableVH.updateView(newView, newLp, context.resources.configuration, null) + reusableVH.updateView(newView, newLp, context.resources.configuration) - assertThat(reusableVH.rootView.childCount).isEqualTo(1) - assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(newView) + assertThat(rootView.childCount).isEqualTo(1) + assertThat(rootView.getChildAt(0)).isEqualTo(newView) + } + + @Test + fun update_sameView_doesNotReplaceView() = runTest { + val view = View(context) + val lp = WindowManager.LayoutParams() + val spyRootView = spy(FrameLayout(context)) + val reusableVH = createReusableViewHost(spyRootView) + reusableVH.updateView(view, lp, context.resources.configuration) + + verify(spyRootView, times(1)).removeAllViews() + assertThat(spyRootView.childCount).isEqualTo(1) + assertThat(spyRootView.getChildAt(0)).isEqualTo(view) + + reusableVH.updateView(view, lp, context.resources.configuration) + + clearInvocations(spyRootView) + verify(spyRootView, never()).removeAllViews() + assertThat(spyRootView.childCount).isEqualTo(1) + assertThat(spyRootView.getChildAt(0)).isEqualTo(view) } @OptIn(ExperimentalCoroutinesApi::class) @Test fun updateView_clearsPendingAsyncJob() = runTest { - val reusableVH = createReusableViewHost() + val rootView = FrameLayout(context) + val reusableVH = createReusableViewHost(rootView) val asyncView = View(context) val syncView = View(context) val asyncAttrs = WindowManager.LayoutParams(100, 100) @@ -83,7 +109,6 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() { view = syncView, attrs = syncAttrs, configuration = context.resources.configuration, - onDrawTransaction = null, ) // Would run coroutine if it hadn't been cancelled. @@ -91,7 +116,7 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() { assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue() // View host view/attrs should match the ones from the sync call. - assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(syncView) + assertThat(rootView.getChildAt(0)).isEqualTo(syncView) assertThat(reusableVH.view()!!.layoutParams.width).isEqualTo(syncAttrs.width) } @@ -118,7 +143,8 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() { @OptIn(ExperimentalCoroutinesApi::class) @Test fun updateViewAsync_clearsPendingAsyncJob() = runTest { - val reusableVH = createReusableViewHost() + val rootView = FrameLayout(context) + val reusableVH = createReusableViewHost(rootView) val view = View(context) reusableVH.updateViewAsync( @@ -136,7 +162,7 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() { advanceUntilIdle() assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue() - assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(otherView) + assertThat(rootView.getChildAt(0)).isEqualTo(otherView) } @Test @@ -148,7 +174,6 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() { view = view, attrs = WindowManager.LayoutParams(100, 100), configuration = context.resources.configuration, - onDrawTransaction = null, ) val t = mock(SurfaceControl.Transaction::class.java) @@ -159,19 +184,23 @@ class ReusableWindowDecorViewHostTest : ShellTestCase() { @Test fun warmUp_addsRootView() = runTest { - val reusableVH = createReusableViewHost().apply { warmUp() } + val rootView = FrameLayout(context) + val reusableVH = createReusableViewHost(rootView).apply { warmUp() } assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue() - assertThat(reusableVH.view()).isEqualTo(reusableVH.rootView) + assertThat(reusableVH.view()).isEqualTo(rootView) } - private fun CoroutineScope.createReusableViewHost() = + private fun CoroutineScope.createReusableViewHost( + rootView: FrameLayout = FrameLayout(context) + ) = ReusableWindowDecorViewHost( context = context, mainScope = this, display = context.display, id = 1, viewHostAdapter = spy(SurfaceControlViewHostAdapter(context, context.display)), + rootView ) private fun ReusableWindowDecorViewHost.view(): View? = viewHostAdapter.viewHost?.view diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index f5e10d94452f..7a51c20f7672 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -44,6 +44,9 @@ namespace android { namespace { +constexpr int32_t kDefaultDisplayId = 0; +constexpr int32_t kDefaultDeviceId = 0; + using EntryValue = std::variant<Res_value, incfs::verified_map_ptr<ResTable_map_entry>>; /* NOTE: table_entry has been verified in LoadedPackage::GetEntryFromOffset(), @@ -61,7 +64,7 @@ base::expected<EntryValue, IOError> GetEntryValue( return table_entry->value(); } -} // namespace +} // namespace struct FindEntryResult { // The cookie representing the ApkAssets in which the value resides. @@ -99,14 +102,15 @@ struct Theme::Entry { Res_value value; }; -AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration) { +AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration) + : display_id_(kDefaultDisplayId), device_id_(kDefaultDeviceId) { configurations_.push_back(configuration); // Don't invalidate caches here as there's nothing cached yet. SetApkAssets(apk_assets, false); } -AssetManager2::AssetManager2() { +AssetManager2::AssetManager2() : display_id_(kDefaultDisplayId), device_id_(kDefaultDeviceId) { configurations_.emplace_back(); } @@ -172,8 +176,7 @@ void AssetManager2::BuildDynamicRefTable(ApkAssetsList apk_assets) { // to take effect. auto iter = target_assets_package_ids.find(loaded_idmap->TargetApkPath()); if (iter == target_assets_package_ids.end()) { - LOG(INFO) << "failed to find target package for overlay " - << loaded_idmap->OverlayApkPath(); + LOG(INFO) << "failed to find target package for overlay " << loaded_idmap->OverlayApkPath(); } else { uint8_t target_package_id = iter->second; @@ -189,10 +192,11 @@ void AssetManager2::BuildDynamicRefTable(ApkAssetsList apk_assets) { << " assigned package group"; PackageGroup& target_package_group = package_groups_[target_idx]; - target_package_group.overlays_.push_back( - ConfiguredOverlay{loaded_idmap->GetTargetResourcesMap(target_package_id, - overlay_ref_table.get()), - apk_assets_cookies[apk_assets]}); + target_package_group.overlays_.push_back(ConfiguredOverlay{ + loaded_idmap->GetTargetResourcesMap(target_package_id, overlay_ref_table.get()), + apk_assets_cookies[apk_assets], + IsAnyOverlayConstraintSatisfied(loaded_idmap->GetConstraints()) + }); } } @@ -291,7 +295,7 @@ void AssetManager2::DumpToLog() const { } LOG(INFO) << "Package ID map: " << list; - for (const auto& package_group: package_groups_) { + for (const auto& package_group : package_groups_) { list = ""; for (const auto& package : package_group.packages_) { const LoadedPackage* loaded_package = package.loaded_package_; @@ -347,7 +351,6 @@ std::shared_ptr<const DynamicRefTable> AssetManager2::GetDynamicRefTableForCooki const std::unordered_map<std::string, std::string>* AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const { - if (package_id >= package_ids_.size()) { return nullptr; } @@ -462,6 +465,28 @@ void AssetManager2::SetConfigurations(std::span<const ResTable_config> configura } } +void AssetManager2::SetOverlayConstraints(int32_t display_id, int32_t device_id) { + bool changed = false; + if (display_id_ != display_id) { + display_id_ = display_id; + changed = true; + } + if (device_id_ != device_id) { + device_id_ = device_id; + changed = true; + } + if (changed) { + // Enable/disable overlays based on current constraints + for (PackageGroup& group : package_groups_) { + for (auto &overlay: group.overlays_) { + overlay.enabled = IsAnyOverlayConstraintSatisfied( + overlay.overlay_res_maps_.GetConstraints()); + } + } + InvalidateCaches(static_cast<uint32_t>(-1)); + } +} + std::set<AssetManager2::ApkAssetsPtr> AssetManager2::GetNonSystemOverlays() const { std::set<ApkAssetsPtr> non_system_overlays; for (const PackageGroup& package_group : package_groups_) { @@ -475,6 +500,8 @@ std::set<AssetManager2::ApkAssetsPtr> AssetManager2::GetNonSystemOverlays() cons if (!found_system_package) { auto op = StartOperation(); + // Return all overlays, including the disabled ones as this is used for static info + // collection only. for (const ConfiguredOverlay& overlay : package_group.overlays_) { if (const auto& asset = GetApkAssets(overlay.cookie)) { non_system_overlays.insert(std::move(asset)); @@ -651,7 +678,6 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry( auto op = StartOperation(); - // Retrieve the package group from the package id of the resource id. if (UNLIKELY(!is_valid_resid(resid))) { LOG(ERROR) << base::StringPrintf("Invalid resource ID 0x%08x.", resid); @@ -672,7 +698,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry( std::optional<FindEntryResult> final_result; bool final_has_locale = false; bool final_overlaid = false; - for (auto & config : configurations_) { + for (auto& config : configurations_) { // Might use this if density_override != 0. ResTable_config density_override_config; @@ -698,7 +724,8 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry( } if (!assets->IsLoader()) { for (const auto& id_map : package_group.overlays_) { - auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid); + auto overlay_entry = id_map.enabled ? + id_map.overlay_res_maps_.Lookup(resid) : IdmapResMap::Result(); if (!overlay_entry) { // No id map entry exists for this target resource. continue; @@ -708,7 +735,7 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry( ConfigDescription best_frro_config; Res_value best_frro_value; bool frro_found = false; - for( const auto& [config, value] : overlay_entry.GetInlineValue()) { + for (const auto& [config, value] : overlay_entry.GetInlineValue()) { if ((!frro_found || config.isBetterThan(best_frro_config, desired_config)) && config.match(*desired_config)) { frro_found = true; @@ -1011,7 +1038,7 @@ std::string AssetManager2::GetLastResourceResolution() const { resid, resource_name_string.c_str(), conf.toString().c_str()); char str[40]; str[0] = '\0'; - for(auto iter = configurations_.begin(); iter < configurations_.end(); iter++) { + for (auto iter = configurations_.begin(); iter < configurations_.end(); iter++) { iter->getBcp47Locale(str); log_stream << base::StringPrintf(" %s%s", str, iter < configurations_.end() ? "," : ""); } @@ -1504,7 +1531,7 @@ void AssetManager2::RebuildFilterList() { package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) { FilteredConfigGroup* group = nullptr; for (const auto& type_entry : type_spec.type_entries) { - for (auto & config : configurations_) { + for (auto& config : configurations_) { if (type_entry.config.match(config)) { if (!group) { group = &package.filtered_configs_.editItemAt(type_id - 1); @@ -1521,6 +1548,27 @@ void AssetManager2::RebuildFilterList() { } } +bool AssetManager2::IsAnyOverlayConstraintSatisfied(const Idmap_constraints& constraints) const { + if (constraints.constraint_count == 0) { + // There are no constraints, return true. + return true; + } + + for (uint32_t i = 0; i < constraints.constraint_count; i++) { + auto constraint = constraints.constraint_entries[i]; + if (constraint.constraint_type == kOverlayConstraintTypeDisplayId && + constraint.constraint_value == display_id_) { + return true; + } + if (constraint.constraint_type == kOverlayConstraintTypeDeviceId && + constraint.constraint_value == device_id_) { + return true; + } + } + + return false; +} + void AssetManager2::InvalidateCaches(uint32_t diff) { cached_resolved_values_.clear(); diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp index f0ef97e5bdcc..8d1de1af56d2 100644 --- a/libs/androidfw/Idmap.cpp +++ b/libs/androidfw/Idmap.cpp @@ -56,13 +56,6 @@ struct Idmap_header { // without having to read/store each header entry separately. }; -struct Idmap_constraint { - // Constraint type can be TYPE_DISPLAY_ID or TYP_DEVICE_ID, please refer - // to ConstraintType in OverlayConstraint.java - uint32_t constraint_type; - uint32_t constraint_value; -}; - struct Idmap_data_header { uint32_t target_entry_count; uint32_t target_inline_entry_count; @@ -148,12 +141,13 @@ status_t OverlayDynamicRefTable::lookupResourceIdNoRewrite(uint32_t* resId) cons return DynamicRefTable::lookupResourceId(resId); } -IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries, - Idmap_target_inline_entries inline_entries, +IdmapResMap::IdmapResMap(const Idmap_data_header* data_header, const Idmap_constraints& constraints, + Idmap_target_entries entries, Idmap_target_inline_entries inline_entries, const Idmap_target_entry_inline_value* inline_entry_values, const ConfigDescription* configs, uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table) : data_header_(data_header), + constraints_(constraints), entries_(entries), inline_entries_(inline_entries), inline_entry_values_(inline_entry_values), @@ -254,7 +248,7 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size } return std::string_view(data, *len); } -} // namespace +} // namespace // O_PATH is a lightweight way of creating an FD, only exists on Linux #ifndef O_PATH @@ -262,9 +256,7 @@ std::optional<std::string_view> ReadString(const uint8_t** in_out_data_ptr, size #endif LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* header, - const Idmap_constraint* constraints, - uint32_t constraints_count, - const Idmap_data_header* data_header, + const Idmap_data_header* data_header, const Idmap_constraints& constraints, Idmap_target_entries target_entries, Idmap_target_inline_entries target_inline_entries, const Idmap_target_entry_inline_value* inline_entry_values, @@ -272,9 +264,8 @@ LoadedIdmap::LoadedIdmap(const std::string& idmap_path, const Idmap_header* head std::unique_ptr<ResStringPool>&& string_pool, std::string_view overlay_apk_path, std::string_view target_apk_path) : header_(header), - constraints_(constraints), - constraints_count_(constraints_count), data_header_(data_header), + constraints_(constraints), target_entries_(target_entries), target_inline_entries_(target_inline_entries), inline_entry_values_(inline_entry_values), @@ -328,16 +319,20 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie return {}; } - auto constraints_count = ReadType<uint32_t>(&data_ptr, &data_size, "constraints count"); - if (!constraints_count) { + auto constraint_count = ReadType<uint32_t>(&data_ptr, &data_size, "constraint count"); + if (!constraint_count) { + LOG(ERROR) << "idmap doesn't have constraint count"; return {}; } - auto constraints = *constraints_count > 0 ? - ReadType<Idmap_constraint>(&data_ptr, &data_size, "constraints", *constraints_count) + auto constraint_entries = *constraint_count > 0 ? + ReadType<Idmap_constraint>(&data_ptr, &data_size, "constraints", dtohl(*constraint_count)) : nullptr; - if (*constraints_count > 0 && !constraints) { + if (*constraint_count > 0 && !constraint_entries) { + LOG(ERROR) << "no constraint entries in idmap with non-zero constraints"; return {}; } + Idmap_constraints constraints{.constraint_count = *constraint_count, + .constraint_entries = constraint_entries}; // Parse the idmap data blocks. Currently idmap2 can only generate one data block. auto data_header = ReadType<Idmap_data_header>(&data_ptr, &data_size, "data header"); @@ -405,10 +400,9 @@ std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPie // Can't use make_unique because LoadedIdmap constructor is private. return std::unique_ptr<LoadedIdmap>( - new LoadedIdmap(std::string(idmap_path), header, constraints, *constraints_count, - data_header, target_entries, target_inline_entries, - target_inline_entry_values,configurations, overlay_entries, - std::move(idmap_string_pool),*overlay_path, *target_path)); + new LoadedIdmap(std::string(idmap_path), header, data_header, constraints, target_entries, + target_inline_entries, target_inline_entry_values, configurations, + overlay_entries, std::move(idmap_string_pool), *overlay_path, *target_path)); } UpToDate LoadedIdmap::IsUpToDate() const { diff --git a/libs/androidfw/LocaleDataLookup.cpp b/libs/androidfw/LocaleDataLookup.cpp index ea9e9a2d4280..9aacdcb9ca92 100644 --- a/libs/androidfw/LocaleDataLookup.cpp +++ b/libs/androidfw/LocaleDataLookup.cpp @@ -14871,12 +14871,22 @@ static uint32_t findLatnParent(uint32_t packed_lang_region) { case 0x656E4154u: // en-AT -> en-150 case 0x656E4245u: // en-BE -> en-150 case 0x656E4348u: // en-CH -> en-150 + case 0x656E435Au: // en-CZ -> en-150 case 0x656E4445u: // en-DE -> en-150 case 0x656E444Bu: // en-DK -> en-150 + case 0x656E4553u: // en-ES -> en-150 case 0x656E4649u: // en-FI -> en-150 + case 0x656E4652u: // en-FR -> en-150 + case 0x656E4855u: // en-HU -> en-150 + case 0x656E4954u: // en-IT -> en-150 case 0x656E4E4Cu: // en-NL -> en-150 + case 0x656E4E4Fu: // en-NO -> en-150 + case 0x656E504Cu: // en-PL -> en-150 + case 0x656E5054u: // en-PT -> en-150 + case 0x656E524Fu: // en-RO -> en-150 case 0x656E5345u: // en-SE -> en-150 case 0x656E5349u: // en-SI -> en-150 + case 0x656E534Bu: // en-SK -> en-150 return 0x656E80A1u; case 0x65734152u: // es-AR -> es-419 case 0x6573424Fu: // es-BO -> es-419 diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 0fdeefa09e26..a47fe6a7f50d 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -171,6 +171,8 @@ class AssetManager2 { default_locale_ = default_locale; } + void SetOverlayConstraints(int32_t display_id, int32_t device_id); + // Returns all configurations for which there are resources defined, or an I/O error if reading // resource data failed. // @@ -389,6 +391,9 @@ class AssetManager2 { // The cookie of the overlay assets. ApkAssetsCookie cookie; + + // Enable/disable status of the overlay based on current constraints of AssetManager. + bool enabled; }; // Represents a logical package, which can be made up of many individual packages. Each package @@ -457,6 +462,8 @@ class AssetManager2 { // promoted apk assets when the last operation ends. void FinishOperation() const; + bool IsAnyOverlayConstraintSatisfied(const Idmap_constraints& constraints) const; + // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must // have a longer lifetime. // The second pair element is the promoted version of the assets, that is held for the duration @@ -480,6 +487,9 @@ class AssetManager2 { // may need to be purged. ftl::SmallVector<ResTable_config, 1> configurations_; + int32_t display_id_; + int32_t device_id_; + // Cached set of bags. These are cached because they can inherit keys from parent bags, // which involves some calculation. mutable std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_; diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h index 0c0856315d8f..939b62462560 100644 --- a/libs/androidfw/include/androidfw/Idmap.h +++ b/libs/androidfw/include/androidfw/Idmap.h @@ -59,13 +59,25 @@ inline UpToDate fromBool(bool value) { class LoadedIdmap; class IdmapResMap; struct Idmap_header; -struct Idmap_constraint; +struct Idmap_constraints; struct Idmap_data_header; -struct Idmap_target_entry; struct Idmap_target_entry_inline; struct Idmap_target_entry_inline_value; -struct Idmap_overlay_entry; +// LINT.IfChange +constexpr int32_t kOverlayConstraintTypeDisplayId = 0; +constexpr int32_t kOverlayConstraintTypeDeviceId = 1; +// LINT.ThenChange(../../../../core/java/android/content/om/OverlayConstraint.java) + +struct Idmap_constraint { + // Constraint type can be kOverlayConstraintTypeDisplayId or kOverlayConstraintTypeDeviceId + const uint32_t constraint_type; + const uint32_t constraint_value; +}; +struct Idmap_constraints { + const uint32_t constraint_count = 0; + const Idmap_constraint* constraint_entries = nullptr; +}; struct Idmap_target_entries { const uint32_t* target_id = nullptr; const uint32_t* overlay_id = nullptr; @@ -169,14 +181,19 @@ class IdmapResMap { return overlay_ref_table_; } + inline Idmap_constraints GetConstraints() const { + return constraints_; + } + private: - explicit IdmapResMap(const Idmap_data_header* data_header, Idmap_target_entries entries, - Idmap_target_inline_entries inline_entries, + explicit IdmapResMap(const Idmap_data_header* data_header, const Idmap_constraints& constraints, + Idmap_target_entries entries, Idmap_target_inline_entries inline_entries, const Idmap_target_entry_inline_value* inline_entry_values, const ConfigDescription* configs, uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table); const Idmap_data_header* data_header_; + Idmap_constraints constraints_; Idmap_target_entries entries_; Idmap_target_inline_entries inline_entries_; const Idmap_target_entry_inline_value* inline_entry_values_; @@ -210,8 +227,9 @@ class LoadedIdmap { // Returns a mapping from target resource ids to overlay values. IdmapResMap GetTargetResourcesMap(uint8_t target_assigned_package_id, const OverlayDynamicRefTable* overlay_ref_table) const { - return IdmapResMap(data_header_, target_entries_, target_inline_entries_, inline_entry_values_, - configurations_, target_assigned_package_id, overlay_ref_table); + return IdmapResMap(data_header_, constraints_, target_entries_, target_inline_entries_, + inline_entry_values_, configurations_, target_assigned_package_id, + overlay_ref_table); } // Returns a dynamic reference table for a loaded overlay package. @@ -223,14 +241,17 @@ class LoadedIdmap { // LoadedIdmap. UpToDate IsUpToDate() const; + inline const Idmap_constraints GetConstraints() const { + return constraints_; + } + protected: // Exposed as protected so that tests can subclass and mock this class out. LoadedIdmap() = default; const Idmap_header* header_; - const Idmap_constraint* constraints_; - uint32_t constraints_count_; const Idmap_data_header* data_header_; + Idmap_constraints constraints_; Idmap_target_entries target_entries_; Idmap_target_inline_entries target_inline_entries_; const Idmap_target_entry_inline_value* inline_entry_values_; @@ -247,9 +268,7 @@ class LoadedIdmap { DISALLOW_COPY_AND_ASSIGN(LoadedIdmap); explicit LoadedIdmap(const std::string& idmap_path, const Idmap_header* header, - const Idmap_constraint* constraints, - uint32_t constraints_count, - const Idmap_data_header* data_header, + const Idmap_data_header* data_header, const Idmap_constraints& constraints, Idmap_target_entries target_entries, Idmap_target_inline_entries target_inline_entries, const Idmap_target_entry_inline_value* inline_entry_values_, diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp index 36feabde07eb..0e52f4e177c5 100644 --- a/libs/hwui/FrameInfo.cpp +++ b/libs/hwui/FrameInfo.cpp @@ -52,8 +52,8 @@ const std::array FrameInfoNames{"Flags", static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 24, "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)"); -void FrameInfo::importUiThreadInfo(int64_t* info) { - memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t)); +void FrameInfo::importUiThreadInfo(const int64_t* info) { + memcpy(mFrameInfo.data(), info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t)); mSkippedFrameReason.reset(); } diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index 61c30b803b00..b1f479faadff 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -84,6 +84,8 @@ enum { }; }; +using FrameInfoBuffer = std::array<int64_t, static_cast<size_t>(FrameInfoIndex::NumIndexes)>; + class UiFrameInfoBuilder { public: static constexpr int64_t INVALID_VSYNC_ID = -1; @@ -132,7 +134,7 @@ private: class FrameInfo { public: - void importUiThreadInfo(int64_t* info); + void importUiThreadInfo(const int64_t* info); void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(SYSTEM_TIME_MONOTONIC); } @@ -152,7 +154,7 @@ public: set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag); } - const int64_t* data() const { return mFrameInfo; } + const FrameInfoBuffer& data() const { return mFrameInfo; } inline int64_t operator[](FrameInfoIndex index) const { return get(index); } @@ -201,7 +203,7 @@ public: } private: - int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::NumIndexes)]; + FrameInfoBuffer mFrameInfo; std::optional<SkippedFrameReason> mSkippedFrameReason; }; diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h index 3ea49518eecd..d267740d15c4 100644 --- a/libs/hwui/FrameMetricsObserver.h +++ b/libs/hwui/FrameMetricsObserver.h @@ -18,12 +18,14 @@ #include <utils/RefBase.h> +#include "FrameInfo.h" + namespace android { namespace uirenderer { class FrameMetricsObserver : public VirtualLightRefBase { public: - virtual void notify(const int64_t* buffer) = 0; + virtual void notify(const FrameInfoBuffer& buffer) = 0; bool waitForPresentTime() const { return mWaitForPresentTime; }; void reportMetricsFrom(uint64_t frameNumber, int32_t surfaceControlId) { diff --git a/libs/hwui/FrameMetricsReporter.cpp b/libs/hwui/FrameMetricsReporter.cpp index ee32ea17bfaf..4ad9c9ad7b31 100644 --- a/libs/hwui/FrameMetricsReporter.cpp +++ b/libs/hwui/FrameMetricsReporter.cpp @@ -16,10 +16,12 @@ #include "FrameMetricsReporter.h" +#include "FrameInfo.h" + namespace android { namespace uirenderer { -void FrameMetricsReporter::reportFrameMetrics(const int64_t* stats, bool hasPresentTime, +void FrameMetricsReporter::reportFrameMetrics(const FrameInfoBuffer& stats, bool hasPresentTime, uint64_t frameNumber, int32_t surfaceControlId) { FatVector<sp<FrameMetricsObserver>, 10> copy; { diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h index 7e51df7ce6fc..71b3f52fe12e 100644 --- a/libs/hwui/FrameMetricsReporter.h +++ b/libs/hwui/FrameMetricsReporter.h @@ -35,12 +35,12 @@ class FrameMetricsReporter { public: FrameMetricsReporter() {} - void addObserver(FrameMetricsObserver* observer) { + void addObserver(sp<FrameMetricsObserver>&& observer) { std::lock_guard lock(mObserversLock); - mObservers.push_back(observer); + mObservers.push_back(std::move(observer)); } - bool removeObserver(FrameMetricsObserver* observer) { + bool removeObserver(const sp<FrameMetricsObserver>& observer) { std::lock_guard lock(mObserversLock); for (size_t i = 0; i < mObservers.size(); i++) { if (mObservers[i].get() == observer) { @@ -69,7 +69,7 @@ public: * stats of frames that are from "old" surfaces (i.e. with surfaceControlIds older than the one * the observer was attached on) nor those that are from "old" frame numbers. */ - void reportFrameMetrics(const int64_t* stats, bool hasPresentTime, uint64_t frameNumber, + void reportFrameMetrics(const FrameInfoBuffer& stats, bool hasPresentTime, uint64_t frameNumber, int32_t surfaceControlId); private: diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig index 7e1f2e2a3490..d3fc91b65829 100644 --- a/libs/hwui/aconfig/hwui_flags.aconfig +++ b/libs/hwui/aconfig/hwui_flags.aconfig @@ -137,6 +137,14 @@ flag { } flag { + name: "shader_color_space" + is_exported: true + namespace: "core_graphics" + description: "API to set the working colorspace of a Shader or ColorFilter" + bug: "299670828" +} + +flag { name: "query_global_priority" namespace: "core_graphics" description: "Attempt to query whether the vulkan driver supports the requested global priority before queue creation." diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp index eadb9dea566f..45f0fe0288a4 100644 --- a/libs/hwui/jni/Shader.cpp +++ b/libs/hwui/jni/Shader.cpp @@ -266,11 +266,17 @@ static jlong RuntimeShader_getNativeFinalizer(JNIEnv*, jobject) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeShaderBuilder_delete)); } -static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr) { +static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderBuilder, jlong matrixPtr, + jlong colorSpacePtr) { SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder); const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr); + auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr); sk_sp<SkShader> shader = builder->makeShader(matrix); ThrowIAE_IfNull(env, shader); + if (colorSpace) { + shader = shader->makeWithWorkingColorSpace(colorSpace); + ThrowIAE_IfNull(env, shader); + } return reinterpret_cast<jlong>(shader.release()); } @@ -350,6 +356,10 @@ static void RuntimeShader_updateChild(JNIEnv* env, jobject, jlong shaderBuilder, UpdateChild(env, builder, name.c_str(), childEffect); } +static void RuntimeShader_no(JNIEnv* env) { + jniThrowRuntimeException(env, "Not supported"); +} + /////////////////////////////////////////////////////////////////////////////////////////////// static const JNINativeMethod gShaderMethods[] = { @@ -379,7 +389,8 @@ static const JNINativeMethod gComposeShaderMethods[] = { static const JNINativeMethod gRuntimeShaderMethods[] = { {"nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer}, - {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_create}, + {"nativeCreateShader", "(JJ)J", (void*)RuntimeShader_no}, + {"nativeCreateShader", "(JJJ)J", (void*)RuntimeShader_create}, {"nativeCreateBuilder", "(Ljava/lang/String;)J", (void*)RuntimeShader_createShaderBuilder}, {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V", (void*)RuntimeShader_updateFloatArrayUniforms}, diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 99e7740d66d2..cfec24b17cd4 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -915,20 +915,22 @@ static jboolean android_view_ThreadedRenderer_isDrawingEnabled(JNIEnv*, jclass) static void android_view_ThreadedRenderer_addObserver(JNIEnv* env, jclass clazz, jlong proxyPtr, jlong observerPtr) { - HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr); + FrameMetricsObserver* rawObserver = reinterpret_cast<FrameMetricsObserver*>(observerPtr); + sp<FrameMetricsObserver> observer = sp<FrameMetricsObserver>::fromExisting(rawObserver); renderthread::RenderProxy* renderProxy = reinterpret_cast<renderthread::RenderProxy*>(proxyPtr); - renderProxy->addFrameMetricsObserver(observer); + renderProxy->addFrameMetricsObserver(std::move(observer)); } static void android_view_ThreadedRenderer_removeObserver(JNIEnv* env, jclass clazz, jlong proxyPtr, jlong observerPtr) { - HardwareRendererObserver* observer = reinterpret_cast<HardwareRendererObserver*>(observerPtr); + FrameMetricsObserver* rawObserver = reinterpret_cast<FrameMetricsObserver*>(observerPtr); + sp<FrameMetricsObserver> observer = sp<FrameMetricsObserver>::fromExisting(rawObserver); renderthread::RenderProxy* renderProxy = reinterpret_cast<renderthread::RenderProxy*>(proxyPtr); - renderProxy->removeFrameMetricsObserver(observer); + renderProxy->removeFrameMetricsObserver(std::move(observer)); } // ---------------------------------------------------------------------------- diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp index 6cae5ffa397f..4f383ee063a2 100644 --- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.cpp @@ -16,11 +16,12 @@ #include "android_graphics_HardwareRendererObserver.h" +#include <array> + +#include "FrameInfo.h" #include "graphics_jni_helpers.h" #include "nativehelper/jni_macros.h" -#include <array> - namespace android { struct { @@ -65,13 +66,13 @@ bool HardwareRendererObserver::getNextBuffer(JNIEnv* env, jlongArray metrics, in return false; } -void HardwareRendererObserver::notify(const int64_t* stats) { +void HardwareRendererObserver::notify(const uirenderer::FrameInfoBuffer& stats) { if (!mKeepListening) return; FrameMetricsNotification& elem = mRingBuffer[mNextFree]; if (!elem.hasData.load()) { - memcpy(elem.buffer, stats, kBufferSize * sizeof(stats[0])); + memcpy(elem.buffer, stats.data(), kBufferSize * sizeof(stats[0])); elem.dropCount = mDroppedReports; mDroppedReports = 0; diff --git a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h index 5ee3e1669502..cf20ee135363 100644 --- a/libs/hwui/jni/android_graphics_HardwareRendererObserver.h +++ b/libs/hwui/jni/android_graphics_HardwareRendererObserver.h @@ -43,7 +43,7 @@ public: */ bool getNextBuffer(JNIEnv* env, jlongArray metrics, int* dropCount); - void notify(const int64_t* stats) override; + void notify(const uirenderer::FrameInfoBuffer& stats) override; private: static constexpr int kBufferSize = static_cast<int>(uirenderer::FrameInfoIndex::NumIndexes); diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index e3e393c4fdfb..b248c4bc9ade 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -859,7 +859,7 @@ void CanvasContext::reportMetricsWithPresentTime() { } // release lock } -void CanvasContext::addFrameMetricsObserver(FrameMetricsObserver* observer) { +void CanvasContext::addFrameMetricsObserver(sp<FrameMetricsObserver>&& observer) { std::scoped_lock lock(mFrameInfoMutex); if (mFrameMetricsReporter.get() == nullptr) { mFrameMetricsReporter.reset(new FrameMetricsReporter()); @@ -870,10 +870,10 @@ void CanvasContext::addFrameMetricsObserver(FrameMetricsObserver* observer) { // their frame metrics. uint64_t nextFrameNumber = getFrameNumber(); observer->reportMetricsFrom(nextFrameNumber, mSurfaceControlGenerationId); - mFrameMetricsReporter->addObserver(observer); + mFrameMetricsReporter->addObserver(std::move(observer)); } -void CanvasContext::removeFrameMetricsObserver(FrameMetricsObserver* observer) { +void CanvasContext::removeFrameMetricsObserver(const sp<FrameMetricsObserver>& observer) { std::scoped_lock lock(mFrameInfoMutex); if (mFrameMetricsReporter.get() != nullptr) { mFrameMetricsReporter->removeObserver(observer); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index cb3753822035..f119102dc2a2 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -176,8 +176,8 @@ public: void setContentDrawBounds(const Rect& bounds) { mContentDrawBounds = bounds; } - void addFrameMetricsObserver(FrameMetricsObserver* observer); - void removeFrameMetricsObserver(FrameMetricsObserver* observer); + void addFrameMetricsObserver(sp<FrameMetricsObserver>&& observer); + void removeFrameMetricsObserver(const sp<FrameMetricsObserver>& observer); // Used to queue up work that needs to be completed before this frame completes void enqueueFrameWork(std::function<void()>&& func); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 715153b5083d..ebfd8fde91f6 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -206,7 +206,7 @@ void RenderProxy::buildLayer(RenderNode* node) { } bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) { - ATRACE_NAME("TextureView#getBitmap"); + ATRACE_NAME("RenderProxy#copyLayerInto readback"); auto& thread = RenderThread::getInstance(); return thread.queue().runSync([&]() -> bool { return thread.readback().copyLayerInto(layer, &bitmap) == CopyResult::Success; @@ -420,15 +420,15 @@ void RenderProxy::setFrameCompleteCallback(std::function<void()>&& callback) { mDrawFrameTask.setFrameCompleteCallback(std::move(callback)); } -void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) { - mRenderThread.queue().post([this, observer = sp{observerPtr}]() { - mContext->addFrameMetricsObserver(observer.get()); +void RenderProxy::addFrameMetricsObserver(sp<FrameMetricsObserver>&& observer) { + mRenderThread.queue().post([this, observer = std::move(observer)]() mutable { + mContext->addFrameMetricsObserver(std::move(observer)); }); } -void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) { - mRenderThread.queue().post([this, observer = sp{observerPtr}]() { - mContext->removeFrameMetricsObserver(observer.get()); +void RenderProxy::removeFrameMetricsObserver(sp<FrameMetricsObserver>&& observer) { + mRenderThread.queue().post([this, observer = std::move(observer)]() { + mContext->removeFrameMetricsObserver(observer); }); } @@ -473,7 +473,7 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) { } int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { - ATRACE_NAME("HardwareBitmap readback"); + ATRACE_NAME("RenderProxy#copyHWBitmapInto readback"); RenderThread& thread = RenderThread::getInstance(); if (RenderThread::isCurrent()) { // TODO: fix everything that hits this. We should never be triggering a readback ourselves. @@ -485,6 +485,7 @@ int RenderProxy::copyHWBitmapInto(Bitmap* hwBitmap, SkBitmap* bitmap) { } int RenderProxy::copyImageInto(const sk_sp<SkImage>& image, SkBitmap* bitmap) { + ATRACE_NAME("RenderProxy#copyImageInto readback"); RenderThread& thread = RenderThread::getInstance(); if (RenderThread::isCurrent()) { // TODO: fix everything that hits this. We should never be triggering a readback ourselves. diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index f2d8e94c7bd2..ad6d54bfcf91 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -141,8 +141,8 @@ public: void setFrameCommitCallback(std::function<void(bool)>&& callback); void setFrameCompleteCallback(std::function<void()>&& callback); - void addFrameMetricsObserver(FrameMetricsObserver* observer); - void removeFrameMetricsObserver(FrameMetricsObserver* observer); + void addFrameMetricsObserver(sp<FrameMetricsObserver>&& observer); + void removeFrameMetricsObserver(sp<FrameMetricsObserver>&& observer); void setForceDark(ForceDarkType type); static void copySurfaceInto(ANativeWindow* window, std::shared_ptr<CopyRequest>&& request); diff --git a/libs/hwui/tests/unit/FrameMetricsReporterTests.cpp b/libs/hwui/tests/unit/FrameMetricsReporterTests.cpp index 571a26707c93..c7935ac5a753 100644 --- a/libs/hwui/tests/unit/FrameMetricsReporterTests.cpp +++ b/libs/hwui/tests/unit/FrameMetricsReporterTests.cpp @@ -14,13 +14,14 @@ * limitations under the License. */ -#include <gmock/gmock.h> -#include <gtest/gtest.h> - #include <FrameMetricsObserver.h> #include <FrameMetricsReporter.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> #include <utils/TimeUtils.h> +#include "FrameInfo.h" + using namespace android; using namespace android::uirenderer; @@ -31,7 +32,7 @@ public: explicit TestFrameMetricsObserver(bool waitForPresentTime) : FrameMetricsObserver(waitForPresentTime){}; - MOCK_METHOD(void, notify, (const int64_t* buffer), (override)); + MOCK_METHOD(void, notify, (const FrameInfoBuffer& buffer), (override)); }; // To make sure it is clear that something went wrong if no from frame is set (to make it easier @@ -44,7 +45,7 @@ TEST(FrameMetricsReporter, doesNotReportAnyFrameIfNoFromFrameIsSpecified) { reporter->addObserver(observer.get()); - const int64_t* stats; + FrameInfoBuffer stats; bool hasPresentTime = false; uint64_t frameNumber = 1; int32_t surfaceControlId = 0; @@ -64,7 +65,7 @@ TEST(FrameMetricsReporter, doesNotReportAnyFrameIfNoFromFrameIsSpecified) { } TEST(FrameMetricsReporter, respectsWaitForPresentTimeUnset) { - const int64_t* stats; + FrameInfoBuffer stats; bool hasPresentTime = false; uint64_t frameNumber = 3; int32_t surfaceControlId = 0; @@ -85,7 +86,7 @@ TEST(FrameMetricsReporter, respectsWaitForPresentTimeUnset) { } TEST(FrameMetricsReporter, respectsWaitForPresentTimeSet) { - const int64_t* stats; + FrameInfoBuffer stats; bool hasPresentTime = true; uint64_t frameNumber = 3; int32_t surfaceControlId = 0; @@ -106,7 +107,7 @@ TEST(FrameMetricsReporter, respectsWaitForPresentTimeSet) { } TEST(FrameMetricsReporter, reportsAllFramesAfterSpecifiedFromFrame) { - const int64_t* stats; + FrameInfoBuffer stats; bool hasPresentTime = false; std::vector<uint64_t> frameNumbers{0, 1, 10}; @@ -138,7 +139,7 @@ TEST(FrameMetricsReporter, reportsAllFramesAfterSpecifiedFromFrame) { } TEST(FrameMetricsReporter, doesNotReportsFramesBeforeSpecifiedFromFrame) { - const int64_t* stats; + FrameInfoBuffer stats; bool hasPresentTime = false; std::vector<uint64_t> frameNumbers{1, 10}; @@ -165,7 +166,7 @@ TEST(FrameMetricsReporter, doesNotReportsFramesBeforeSpecifiedFromFrame) { } TEST(FrameMetricsReporter, canRemoveObservers) { - const int64_t* stats; + FrameInfoBuffer stats; bool hasPresentTime = false; uint64_t frameNumber = 3; int32_t surfaceControlId = 0; @@ -187,7 +188,7 @@ TEST(FrameMetricsReporter, canRemoveObservers) { } TEST(FrameMetricsReporter, canSupportMultipleObservers) { - const int64_t* stats; + FrameInfoBuffer stats; bool hasPresentTime = false; uint64_t frameNumber = 3; int32_t surfaceControlId = 0; diff --git a/libs/hwui/tests/unit/JankTrackerTests.cpp b/libs/hwui/tests/unit/JankTrackerTests.cpp index c289d67fbef6..08718c959150 100644 --- a/libs/hwui/tests/unit/JankTrackerTests.cpp +++ b/libs/hwui/tests/unit/JankTrackerTests.cpp @@ -14,18 +14,19 @@ * limitations under the License. */ -#include <gtest/gtest.h> -#include <gmock/gmock.h> - #include <JankTracker.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> #include <utils/TimeUtils.h> +#include "FrameInfo.h" + using namespace android; using namespace android::uirenderer; class TestFrameMetricsObserver : public FrameMetricsObserver { public: - void notify(const int64_t*) {} + void notify(const FrameInfoBuffer&) override {} }; TEST(JankTracker, noJank) { diff --git a/location/Android.bp b/location/Android.bp index bc02d1f852de..80556a2376bf 100644 --- a/location/Android.bp +++ b/location/Android.bp @@ -42,6 +42,7 @@ java_sdk_library { "FlaggedApi", ], }, + jarjar_prefix: "com.android.internal.hidden_from_bootclasspath", } platform_compat_config { diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java index e1fbfea19235..892a8612d74a 100644 --- a/media/java/android/media/AudioDeviceVolumeManager.java +++ b/media/java/android/media/AudioDeviceVolumeManager.java @@ -86,10 +86,10 @@ public class AudioDeviceVolumeManager { /** * @hide * Interface to receive volume changes on a device that behaves in absolute volume mode. - * @see #setDeviceAbsoluteMultiVolumeBehavior(AudioDeviceAttributes, List, Executor, - * OnAudioDeviceVolumeChangeListener) - * @see #setDeviceAbsoluteVolumeBehavior(AudioDeviceAttributes, VolumeInfo, Executor, - * OnAudioDeviceVolumeChangeListener) + * @see #setDeviceAbsoluteMultiVolumeBehavior(AudioDeviceAttributes, List, boolean, Executor, + * OnAudioDeviceVolumeChangedListener) + * @see #setDeviceAbsoluteVolumeBehavior(AudioDeviceAttributes, VolumeInfo, boolean, Executor, + * OnAudioDeviceVolumeChangedListener) */ public interface OnAudioDeviceVolumeChangedListener { /** @@ -203,6 +203,9 @@ public class AudioDeviceVolumeManager { * volume updates to apply on that device * @param device the audio device set to absolute volume mode * @param volume the type of volume this device responds to + * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately + * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume} + * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}. * @param executor the Executor used for receiving volume updates through the listener * @param vclistener the callback for volume updates */ @@ -211,13 +214,13 @@ public class AudioDeviceVolumeManager { public void setDeviceAbsoluteVolumeBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { + @NonNull OnAudioDeviceVolumeChangedListener vclistener) { final ArrayList<VolumeInfo> volumes = new ArrayList<>(1); volumes.add(volume); - setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener, - handlesVolumeAdjustment); + setDeviceAbsoluteMultiVolumeBehavior(device, volumes, handlesVolumeAdjustment, executor, + vclistener); } /** @@ -226,20 +229,20 @@ public class AudioDeviceVolumeManager { * registers a listener for receiving volume updates to apply on that device * @param device the audio device set to absolute multi-volume mode * @param volumes the list of volumes the given device responds to + * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately + * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume} + * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}. * @param executor the Executor used for receiving volume updates through the listener * @param vclistener the callback for volume updates - * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately - * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume} - * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}. */ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING, android.Manifest.permission.BLUETOOTH_PRIVILEGED }) public void setDeviceAbsoluteMultiVolumeBehavior( @NonNull AudioDeviceAttributes device, @NonNull List<VolumeInfo> volumes, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { + @NonNull OnAudioDeviceVolumeChangedListener vclistener) { baseSetDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener, handlesVolumeAdjustment, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); } @@ -249,11 +252,14 @@ public class AudioDeviceVolumeManager { * Configures a device to use absolute volume model, and registers a listener for receiving * volume updates to apply on that device. * - * Should be used instead of {@link #setDeviceAbsoluteVolumeBehavior} when there is no reliable - * way to set the device's volume to a percentage. + * <p>Should be used instead of {@link #setDeviceAbsoluteVolumeBehavior} when there is no + * reliable way to set the device's volume to a percentage. * * @param device the audio device set to absolute volume mode * @param volume the type of volume this device responds to + * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately + * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume} + * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}. * @param executor the Executor used for receiving volume updates through the listener * @param vclistener the callback for volume updates */ @@ -262,13 +268,13 @@ public class AudioDeviceVolumeManager { public void setDeviceAbsoluteVolumeAdjustOnlyBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { + @NonNull OnAudioDeviceVolumeChangedListener vclistener) { final ArrayList<VolumeInfo> volumes = new ArrayList<>(1); volumes.add(volume); - setDeviceAbsoluteMultiVolumeAdjustOnlyBehavior(device, volumes, executor, vclistener, - handlesVolumeAdjustment); + setDeviceAbsoluteMultiVolumeAdjustOnlyBehavior(device, volumes, handlesVolumeAdjustment, + executor, vclistener); } /** @@ -276,11 +282,14 @@ public class AudioDeviceVolumeManager { * Configures a device to use absolute volume model applied to different volume types, and * registers a listener for receiving volume updates to apply on that device. * - * Should be used instead of {@link #setDeviceAbsoluteMultiVolumeBehavior} when there is + * <p>Should be used instead of {@link #setDeviceAbsoluteMultiVolumeBehavior} when there is * no reliable way to set the device's volume to a percentage. * * @param device the audio device set to absolute multi-volume mode * @param volumes the list of volumes the given device responds to + * @param handlesVolumeAdjustment whether the controller handles volume adjustments separately + * from volume changes. If true, adjustments from {@link AudioManager#adjustStreamVolume} + * will be sent via {@link OnAudioDeviceVolumeChangedListener#onAudioDeviceVolumeAdjusted}. * @param executor the Executor used for receiving volume updates through the listener * @param vclistener the callback for volume updates */ @@ -289,16 +298,16 @@ public class AudioDeviceVolumeManager { public void setDeviceAbsoluteMultiVolumeAdjustOnlyBehavior( @NonNull AudioDeviceAttributes device, @NonNull List<VolumeInfo> volumes, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { + @NonNull OnAudioDeviceVolumeChangedListener vclistener) { baseSetDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener, handlesVolumeAdjustment, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); } /** * Base method for configuring a device to use absolute volume behavior, or one of its variants. - * See {@link AudioManager#AbsoluteDeviceVolumeBehavior} for a list of allowed behaviors. + * See {@link AudioManager.AbsoluteDeviceVolumeBehavior} for a list of allowed behaviors. * * @param behavior the variant of absolute device volume behavior to adopt */ diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 12d7f33a0d51..e01cb928e369 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -1754,13 +1754,21 @@ public class AudioSystem @UnsupportedAppUsage public static int setDeviceConnectionState(AudioDeviceAttributes attributes, int state, int codecFormat) { + return setDeviceConnectionState(attributes, state, codecFormat, false /*deviceSwitch*/); + } + + /** + * @hide + */ + public static int setDeviceConnectionState(AudioDeviceAttributes attributes, int state, + int codecFormat, boolean deviceSwitch) { android.media.audio.common.AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes); Parcel parcel = Parcel.obtain(); port.writeToParcel(parcel, 0); parcel.setDataPosition(0); try { - return setDeviceConnectionState(state, parcel, codecFormat); + return setDeviceConnectionState(state, parcel, codecFormat, deviceSwitch); } finally { parcel.recycle(); } @@ -1769,7 +1777,10 @@ public class AudioSystem * @hide */ @UnsupportedAppUsage - public static native int setDeviceConnectionState(int state, Parcel parcel, int codecFormat); + public static native int setDeviceConnectionState(int state, Parcel parcel, int codecFormat, + boolean deviceSwitch); + + /** @hide */ @UnsupportedAppUsage public static native int getDeviceConnectionState(int device, String device_address); diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 23f87abaffed..b8259ef45de4 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -2037,9 +2037,10 @@ public class ExifInterface { // Ignore exceptions in order to keep the compatibility with the old versions of // ExifInterface. mIsSupportedFile = false; - Log.w(TAG, "Invalid image: ExifInterface got an unsupported image format file" - + "(ExifInterface supports JPEG and some RAW image formats only) " - + "or a corrupted JPEG file to ExifInterface.", e); + Log.d( + TAG, + "Invalid image: ExifInterface got an unsupported or corrupted image file", + e); } finally { addDefaultValuesForCompatibility(); diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java index 88981eac9bb5..1cb540b09fb3 100644 --- a/media/java/android/media/MediaRoute2Info.java +++ b/media/java/android/media/MediaRoute2Info.java @@ -481,9 +481,9 @@ public final class MediaRoute2Info implements Parcelable { /** * Indicates that a route supports routing playback to remote routes through control commands. * - * <p>This type of routing does not affect affect this system's audio or video, but instead - * relies on the device that corresponds to this route to fetch and play the media. It also - * requires the media app to take care of initializing and controlling playback. + * <p>This type of routing does not affect this system's audio or video, but instead relies on + * the device that corresponds to this route to fetch and play the media. It also requires the + * media app to take care of initializing and controlling playback. */ @FlaggedApi(FLAG_ENABLE_MIRRORING_IN_MEDIA_ROUTER_2) public static final int FLAG_ROUTING_TYPE_REMOTE = 1 << 2; diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java index e94fb7d9e52b..4ae8daa63e1d 100644 --- a/media/java/android/media/MediaRoute2ProviderService.java +++ b/media/java/android/media/MediaRoute2ProviderService.java @@ -348,18 +348,21 @@ public abstract class MediaRoute2ProviderService extends Service { * <p>This method must only be called as the result of a prior call to {@link * #onCreateSystemRoutingSession}. * + * <p>This method returns a {@link MediaStreams} instance that holds the media streams to route + * as part of the newly created routing session. May be null if system media capture failed, in + * which case you can ignore the return value, as you will receive a call to {@link + * #onReleaseSession} where you can clean up this session. {@link AudioRecord#startRecording()} + * must be called immediately on {@link MediaStreams#getAudioRecord()} after calling this + * method, in order to start streaming audio to the receiver. + * * @param requestId the ID of the {@link #onCreateSystemRoutingSession} request which this call * is in response to. * @param sessionInfo a {@link RoutingSessionInfo} that describes the newly created routing * session. * @param formats the {@link MediaStreamsFormats} that describes the format for the {@link * MediaStreams} to return. - * @return a {@link MediaStreams} instance that holds the media streams to route as part of the - * newly created routing session. May be null if system media capture failed, in which case - * you can ignore the return value, as you will receive a call to {@link #onReleaseSession} - * where you can clean up this session. {@link AudioRecord#startRecording()} must be called - * immediately on {@link MediaStreams#getAudioRecord()} after calling this method, in order - * to start streaming audio to the receiver. + * @return The {@link MediaStreams} to route as part of the new session, or null if system media + * capture failed and the result can be ignored. * @throws IllegalStateException If the provided {@code requestId} doesn't correspond to a * previous call to {@link #onCreateSystemRoutingSession}. */ @@ -1191,8 +1194,8 @@ public abstract class MediaRoute2ProviderService extends Service { * * <p>The default value is an empty {@link Bundle}. * - * <p>Note that this bundle is not copied, so avoiding mutating the given {@link Bundle} - * after passing it to this method. + * <p>Do not mutate the given {@link Bundle} after passing it to this method. You can + * use {@link Bundle#deepCopy()} to keep a mutable copy. */ @NonNull public Builder setExtras(@NonNull Bundle extras) { diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index 4fe0b80f3951..275972495206 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -715,47 +715,45 @@ void ASurfaceTransaction_setLuts(ASurfaceTransaction* aSurfaceTransaction, sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); - int fd = -1; + base::unique_fd fd; std::vector<int32_t> offsets; std::vector<int32_t> dimensions; std::vector<int32_t> sizes; std::vector<int32_t> samplingKeys; if (luts) { - std::vector<float> buffer(luts->totalBufferSize); int32_t count = luts->offsets.size(); offsets = luts->offsets; dimensions.reserve(count); sizes.reserve(count); samplingKeys.reserve(count); - for (int32_t i = 0; i < count; i++) { - dimensions.emplace_back(luts->entries[i]->properties.dimension); - sizes.emplace_back(luts->entries[i]->properties.size); - samplingKeys.emplace_back(luts->entries[i]->properties.samplingKey); - std::copy(luts->entries[i]->buffer.data.begin(), luts->entries[i]->buffer.data.end(), - buffer.begin() + offsets[i]); - } // mmap - fd = ashmem_create_region("lut_shared_mem", luts->totalBufferSize * sizeof(float)); + fd.reset(ashmem_create_region("lut_shared_mem", luts->totalBufferSize * sizeof(float))); if (fd < 0) { LOG_ALWAYS_FATAL("setLuts, ashmem_create_region() failed"); return; } - void* ptr = mmap(nullptr, luts->totalBufferSize * sizeof(float), PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); + float* ptr = (float*)mmap(nullptr, luts->totalBufferSize * sizeof(float), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (ptr == MAP_FAILED) { LOG_ALWAYS_FATAL("setLuts, Failed to map the shared memory"); return; } - memcpy(ptr, buffer.data(), luts->totalBufferSize * sizeof(float)); + for (int32_t i = 0; i < count; i++) { + dimensions.emplace_back(luts->entries[i]->properties.dimension); + sizes.emplace_back(luts->entries[i]->properties.size); + samplingKeys.emplace_back(luts->entries[i]->properties.samplingKey); + std::copy(luts->entries[i]->buffer.data.begin(), luts->entries[i]->buffer.data.end(), + ptr + offsets[i]); + } + munmap(ptr, luts->totalBufferSize * sizeof(float)); } - transaction->setLuts(surfaceControl, base::unique_fd(fd), offsets, dimensions, sizes, - samplingKeys); + transaction->setLuts(surfaceControl, std::move(fd), offsets, dimensions, sizes, samplingKeys); } void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction, diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml index d002c9ce0f82..c5ed386799dd 100644 --- a/packages/CompanionDeviceManager/res/values-hr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml @@ -27,7 +27,7 @@ <string name="chooser_title_non_profile" msgid="6035023914517087400">"Odaberite uređaj kojim će upravljati aplikacija <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>"</string> <string name="chooser_title" msgid="2235819929238267637">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> koji želite postaviti"</string> <string name="single_device_title" msgid="4199861437545438606">"Traži se <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> - <string name="summary_watch" msgid="8134580124808507407">"Aplikacija će moći sinkronizirati podatke kao što je ime pozivatelja i pristupiti tim dopuštenjima na vašem uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string> + <string name="summary_watch" msgid="8134580124808507407">"Aplikacija će moći sinkronizirati podatke kao što je ime pozivatelja i pristupiti tim dopuštenjima na vašem <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string> <string name="confirmation_title_glasses" msgid="8288346850537727333">"Dopustiti aplikaciji <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> da upravlja uređajem <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>?"</string> <string name="profile_name_glasses" msgid="3506504967216601277">"uređaj"</string> <string name="summary_glasses" msgid="5469208629679579157">"Aplikacija će moći pristupati ovim dopuštenjima na vašem uređaju <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>"</string> diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml index 77e2396cd3c9..3f6eacfb4c44 100644 --- a/packages/CompanionDeviceManager/res/values-km/strings.xml +++ b/packages/CompanionDeviceManager/res/values-km/strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"កម្មវិធីគ្រប់គ្រងឧបករណ៍ដៃគូ"</string> <string name="confirmation_title" msgid="2244241995958340998">"អនុញ្ញាតឱ្យកម្មវិធី <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> ចូលប្រើ <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> ឬ?"</string> - <string name="message_discovery_soft_timeout" msgid="473346859407859161">"សូមប្រាកដថា<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>នេះបានបើក<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> និងទុក<xliff:g id="PROFILE_NAME">%3$s</xliff:g>នៅជិតអ្នក។"</string> + <string name="message_discovery_soft_timeout" msgid="473346859407859161">"សូមប្រាកដថា<xliff:g id="DEVICE_TYPE">%1$s</xliff:g>នេះបានបើក<xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> និងទុក<xliff:g id="PROFILE_NAME">%3$s</xliff:g>របស់អ្នកនៅជិតអ្នក។"</string> <string name="message_discovery_hard_timeout" msgid="677514663495711424">"រកមិនឃើញឧបករណ៍ទេ។ សូមព្យាយាមម្ដងទៀតនៅពេលក្រោយ។"</string> <string name="discovery_bluetooth" msgid="5693557668470016164">"ប៊្លូធូស"</string> <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string> diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml index ee4db7d681ad..0b4274e7bc05 100644 --- a/packages/CompanionDeviceManager/res/values-ko/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml @@ -18,12 +18,12 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4470785958457506021">"부속 기기 관리자"</string> <string name="confirmation_title" msgid="2244241995958340998">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> 앱에서 <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong>에 액세스하도록 허용하시겠습니까?"</string> - <string name="message_discovery_soft_timeout" msgid="473346859407859161">"이 <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>에서 <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> 기능을 사용 설정하고 <xliff:g id="PROFILE_NAME">%3$s</xliff:g> 기기를 근처에 두세요."</string> + <string name="message_discovery_soft_timeout" msgid="473346859407859161">"이 <xliff:g id="DEVICE_TYPE">%1$s</xliff:g>에서 <xliff:g id="DISCOVERY_METHOD">%2$s</xliff:g> 기능을 사용 설정하고 <xliff:g id="PROFILE_NAME">%3$s</xliff:g>을(를) 근처에 두세요."</string> <string name="message_discovery_hard_timeout" msgid="677514663495711424">"기기를 찾을 수 없습니다. 나중에 다시 시도해 주세요."</string> <string name="discovery_bluetooth" msgid="5693557668470016164">"블루투스"</string> <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string> <string name="discovery_mixed" msgid="7071466134150760127">"블루투스 및 Wi-Fi"</string> - <string name="profile_name_watch" msgid="576290739483672360">"시계"</string> + <string name="profile_name_watch" msgid="576290739483672360">"워치"</string> <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong>에서 관리할 기기 선택"</string> <string name="chooser_title" msgid="2235819929238267637">"설정할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g> 선택"</string> <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> 찾는 중"</string> diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml index 8ba76bc40653..86c0e46a2ea3 100644 --- a/packages/CompanionDeviceManager/res/values-tr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml @@ -23,7 +23,7 @@ <string name="discovery_bluetooth" msgid="5693557668470016164">"Bluetooth"</string> <string name="discovery_wifi" msgid="1551782459721758773">"Kablosuz"</string> <string name="discovery_mixed" msgid="7071466134150760127">"Bluetooth ve Kablosuz"</string> - <string name="profile_name_watch" msgid="576290739483672360">"saat"</string> + <string name="profile_name_watch" msgid="576290739483672360">"Saat"</string> <string name="chooser_title_non_profile" msgid="6035023914517087400">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> tarafından yönetilecek bir cihaz seçin"</string> <string name="chooser_title" msgid="2235819929238267637">"Ayarlamak için bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string> <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> aranıyor"</string> diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml index f517742973ff..8c50d8133fc0 100644 --- a/packages/CompanionDeviceManager/res/values-ur/strings.xml +++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml @@ -23,9 +23,9 @@ <string name="discovery_bluetooth" msgid="5693557668470016164">"بلوٹوتھ"</string> <string name="discovery_wifi" msgid="1551782459721758773">"Wi-Fi"</string> <string name="discovery_mixed" msgid="7071466134150760127">"بلوٹوتھ اور Wi-Fi"</string> - <string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string> + <string name="profile_name_watch" msgid="576290739483672360">"گھڑی"</string> <string name="chooser_title_non_profile" msgid="6035023914517087400">"کوئی آلہ منتخب کریں جس کا نظم و نسق <strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کرے"</string> - <string name="chooser_title" msgid="2235819929238267637">"سیٹ اپ کرنے کے لیے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کا انتخاب کریں"</string> + <string name="chooser_title" msgid="2235819929238267637">"سیٹ اپ کرنے کے لیے ایک <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کا انتخاب کریں"</string> <string name="single_device_title" msgid="4199861437545438606">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو تلاش کیا جا رہا ہے"</string> <string name="summary_watch" msgid="8134580124808507407">"اس ایپ کو آپ کے <xliff:g id="DEVICE_TYPE">%1$s</xliff:g> پر کسی کال کرنے والے کے نام جیسی معلومات کی مطابقت پذیری کرنے اور ان اجازتوں تک رسائی کی اجازت ہوگی"</string> <string name="confirmation_title_glasses" msgid="8288346850537727333">"<strong><xliff:g id="APP_NAME">%1$s</xliff:g></strong> کو <strong><xliff:g id="DEVICE_NAME">%2$s</xliff:g></strong> کا نظم کرنے کی اجازت دیں؟"</string> diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt index d6e19a6193fd..a75aeaff0c48 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/WearApp.kt @@ -104,6 +104,7 @@ fun WearApp( scrollable(Screen.MultipleCredentialsScreenFlatten.route) { MultiCredentialsFlattenScreen( credentialSelectorUiState = (remember { uiState } as MultipleEntry), + columnState = it.columnState, flowEngine = flowEngine, ) } diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt index 932b3456bfb8..96cadab3916a 100644 --- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt +++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/multiple/MultiCredentialsFlattenScreen.kt @@ -36,7 +36,7 @@ import com.android.credentialmanager.model.get.CredentialEntryInfo import com.android.credentialmanager.ui.components.CredentialsScreenChipSpacer import com.google.android.horologist.annotations.ExperimentalHorologistApi import com.google.android.horologist.compose.layout.ScalingLazyColumn -import com.google.android.horologist.compose.layout.rememberColumnState +import com.google.android.horologist.compose.layout.ScalingLazyColumnState import com.google.android.horologist.compose.layout.ScalingLazyColumnDefaults import androidx.compose.ui.text.style.TextAlign import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme @@ -45,6 +45,7 @@ import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme * Screen that shows multiple credentials to select from, grouped by accounts * * @param credentialSelectorUiState The app bar view model. + * @param columnState ScalingLazyColumn configuration to be be applied * @param modifier styling for composable * @param flowEngine [FlowEngine] that updates ui state for this screen */ @@ -52,15 +53,14 @@ import androidx.wear.compose.material.MaterialTheme as WearMaterialTheme @Composable fun MultiCredentialsFlattenScreen( credentialSelectorUiState: MultipleEntry, + columnState: ScalingLazyColumnState, flowEngine: FlowEngine, ) { val selectEntry = flowEngine.getEntrySelector() Row { Spacer(Modifier.weight(0.052f)) // 5.2% side margin ScalingLazyColumn( - columnState = rememberColumnState( - ScalingLazyColumnDefaults.belowTimeText(horizontalAlignment = Alignment.Start), - ), + columnState = columnState, modifier = Modifier.weight(0.896f).fillMaxSize(), // 5.2% side margin ) { diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp index bd892637a5eb..853d1ad0dc94 100644 --- a/packages/CtsShim/build/Android.bp +++ b/packages/CtsShim/build/Android.bp @@ -152,34 +152,6 @@ android_app { } //########################################################## -// Variant: System app upgrade - -android_app { - name: "CtsShimUpgrade", - - sdk_version: "current", - optimize: { - enabled: false, - }, - dex_preopt: { - enabled: false, - }, - - manifest: "shim/AndroidManifestUpgrade.xml", - min_sdk_version: "24", -} - -java_genrule { - name: "generate_shim_manifest", - srcs: [ - "shim/AndroidManifest.xml", - ":CtsShimUpgrade", - ], - out: ["AndroidManifest.xml"], - cmd: "sed -e s/__HASH__/`sha512sum -b $(location :CtsShimUpgrade) | cut -d' ' -f1`/ $(location shim/AndroidManifest.xml) > $(out)", -} - -//########################################################## // Variant: System app android_app { @@ -193,7 +165,7 @@ android_app { enabled: false, }, - manifest: ":generate_shim_manifest", + manifest: "shim/AndroidManifest.xml", apex_available: [ "//apex_available:platform", "com.android.apex.cts.shim.v1", diff --git a/packages/CtsShim/build/shim/AndroidManifest.xml b/packages/CtsShim/build/shim/AndroidManifest.xml index 3b8276b66bac..1ffe56c0c76a 100644 --- a/packages/CtsShim/build/shim/AndroidManifest.xml +++ b/packages/CtsShim/build/shim/AndroidManifest.xml @@ -17,15 +17,13 @@ <!-- Manifest for the system CTS shim --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" - package="com.android.cts.ctsshim" - android:sharedUserId="com.android.cts.ctsshim" > + package="com.android.cts.ctsshim" > - <uses-sdk - android:minSdkVersion="24" + <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="28" /> <restrict-update - android:hash="__HASH__" /> + android:hash="__CAN_NOT_BE_UPDATED__" /> <application android:hasCode="false" diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml index e364576c4001..273cfa003c08 100644 --- a/packages/InputDevices/res/values-af/strings.xml +++ b/packages/InputDevices/res/values-af/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serwies (Cyrillies)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegryns (Cyrillies)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Roemeens"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml index db5a7d404a58..859325387dff 100644 --- a/packages/InputDevices/res/values-am/strings.xml +++ b/packages/InputDevices/res/values-am/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ሰርቢያኛ (ሲሪሊክኛ)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ሞንቴኔግሮኛ (ሲሪሊክኛ)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ሮማኒያኛ"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml index 6d917da5b814..67b7b6a263dc 100644 --- a/packages/InputDevices/res/values-ar/strings.xml +++ b/packages/InputDevices/res/values-ar/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"الصربية (السيريلية)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"لغة الجبل الأسود (السيريلية)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"الرومانية"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"الإنجليزية (الهند)"</string> </resources> diff --git a/packages/InputDevices/res/values-as/strings.xml b/packages/InputDevices/res/values-as/strings.xml index c4eaafb195c9..e6540e486055 100644 --- a/packages/InputDevices/res/values-as/strings.xml +++ b/packages/InputDevices/res/values-as/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ছাৰ্বিয়ান (চিৰিলিক)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"মণ্টেনেগ্ৰিণ (চিৰিলিক)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ৰোমানিয়ান"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-az/strings.xml b/packages/InputDevices/res/values-az/strings.xml index d71c3960601d..aa93a92b994e 100644 --- a/packages/InputDevices/res/values-az/strings.xml +++ b/packages/InputDevices/res/values-az/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serb dili (Kiril)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Monteneqro dili (Kiril)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumın dili"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-b+sr+Latn/strings.xml b/packages/InputDevices/res/values-b+sr+Latn/strings.xml index e670ed4f843c..1d21a0676ce5 100644 --- a/packages/InputDevices/res/values-b+sr+Latn/strings.xml +++ b/packages/InputDevices/res/values-b+sr+Latn/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srpski (ćirilica)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"crnogorski (ćirilica)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunski"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"engleski (Indija)"</string> </resources> diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml index c8c04d400eb8..b374a61951c7 100644 --- a/packages/InputDevices/res/values-be/strings.xml +++ b/packages/InputDevices/res/values-be/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербская (кірыліца)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Чарнагорская (кірыліца)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румынская"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Англійская (Індыя)"</string> </resources> diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml index 82c39657b003..ceb7e376280f 100644 --- a/packages/InputDevices/res/values-bg/strings.xml +++ b/packages/InputDevices/res/values-bg/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"сръбски (кирилица)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"черногорски (кирилица)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"румънски"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-bn/strings.xml b/packages/InputDevices/res/values-bn/strings.xml index de54cdf688c4..369a8035dab8 100644 --- a/packages/InputDevices/res/values-bn/strings.xml +++ b/packages/InputDevices/res/values-bn/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"সার্বিয়ান (সিরিলিক)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"মন্টেনেগ্রিন (সিরিলিক)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"রোমানিয়ান"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-bs/strings.xml b/packages/InputDevices/res/values-bs/strings.xml index 9b7b33112643..6b6b23fa1f2a 100644 --- a/packages/InputDevices/res/values-bs/strings.xml +++ b/packages/InputDevices/res/values-bs/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srpski (ćirilica)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"crnogorski (ćirilica)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunski"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"engleski (Indija)"</string> </resources> diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml index 874e06bb69cf..bbf39467284f 100644 --- a/packages/InputDevices/res/values-ca/strings.xml +++ b/packages/InputDevices/res/values-ca/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbi (ciríl·lic)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrí (ciríl·lic)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanès"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml index c7a489672bb0..e88aa9723e9c 100644 --- a/packages/InputDevices/res/values-cs/strings.xml +++ b/packages/InputDevices/res/values-cs/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srbština (cyrilice)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"černohorština (cyrilice)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunština"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"angličtina (Indie)"</string> </resources> diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml index 246baba5be18..00a2a62091af 100644 --- a/packages/InputDevices/res/values-da/strings.xml +++ b/packages/InputDevices/res/values-da/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisk (kyrillisk)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrinsk (kyrillisk)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumænsk"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml index 21a939a3d007..717c5975a75f 100644 --- a/packages/InputDevices/res/values-de/strings.xml +++ b/packages/InputDevices/res/values-de/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisch (kyrillisch)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrinisch (kyrillisch)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumänisch"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml index eabb90c86daf..02b7f1f8a9fd 100644 --- a/packages/InputDevices/res/values-el/strings.xml +++ b/packages/InputDevices/res/values-el/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Σερβικά (Κυριλλικά)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Μαυροβουνιακά (Κυριλλικά)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Ρουμανικά"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-en-rAU/strings.xml b/packages/InputDevices/res/values-en-rAU/strings.xml index 7b72cba5c863..1cdcc552d5ee 100644 --- a/packages/InputDevices/res/values-en-rAU/strings.xml +++ b/packages/InputDevices/res/values-en-rAU/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-en-rCA/strings.xml b/packages/InputDevices/res/values-en-rCA/strings.xml index d78dce2ff927..36e098818f92 100644 --- a/packages/InputDevices/res/values-en-rCA/strings.xml +++ b/packages/InputDevices/res/values-en-rCA/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"English (India)"</string> </resources> diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml index 7b72cba5c863..1cdcc552d5ee 100644 --- a/packages/InputDevices/res/values-en-rGB/strings.xml +++ b/packages/InputDevices/res/values-en-rGB/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml index 7b72cba5c863..1cdcc552d5ee 100644 --- a/packages/InputDevices/res/values-en-rIN/strings.xml +++ b/packages/InputDevices/res/values-en-rIN/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml index 2a4035ad5eed..edd76575215e 100644 --- a/packages/InputDevices/res/values-es-rUS/strings.xml +++ b/packages/InputDevices/res/values-es-rUS/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbio (cirílico)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumano"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml index ba1ef20e24b6..b522845ebacb 100644 --- a/packages/InputDevices/res/values-es/strings.xml +++ b/packages/InputDevices/res/values-es/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbio (cirílico)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumano"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-et/strings.xml b/packages/InputDevices/res/values-et/strings.xml index 99f36260cc41..82670ddd339e 100644 --- a/packages/InputDevices/res/values-et/strings.xml +++ b/packages/InputDevices/res/values-et/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"serbia (kirillitsa)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"montenegro (kirillitsa)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumeenia"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml index 9fae4f99b09d..b777b8c21ad9 100644 --- a/packages/InputDevices/res/values-eu/strings.xml +++ b/packages/InputDevices/res/values-eu/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbiarra (zirilikoa)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegroarra (zirilikoa)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Errumaniera"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml index cbc6b65148b9..9ec7a34193bc 100644 --- a/packages/InputDevices/res/values-fa/strings.xml +++ b/packages/InputDevices/res/values-fa/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"صربی (سیریلیک)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"مونتهنگرویی (سیریلیک)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"رومانیایی"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml index 736d7cbd77c3..6825ea9396bf 100644 --- a/packages/InputDevices/res/values-fi/strings.xml +++ b/packages/InputDevices/res/values-fi/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"serbia (kyrillinen)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"montenegro (kyrillinen)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"romania"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml index 7b99d3bc33bc..353d7ad83cca 100644 --- a/packages/InputDevices/res/values-fr-rCA/strings.xml +++ b/packages/InputDevices/res/values-fr-rCA/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbe (cyrillique)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Monténégrin (cyrillique)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Roumain"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Anglais (Inde)"</string> </resources> diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml index 8628f8f7c0eb..fb4d1442d71f 100644 --- a/packages/InputDevices/res/values-fr/strings.xml +++ b/packages/InputDevices/res/values-fr/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbe (cyrillique)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Monténégrin (cyrillique)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Roumain"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-gl/strings.xml b/packages/InputDevices/res/values-gl/strings.xml index 5e681e6032dc..925adf9466f9 100644 --- a/packages/InputDevices/res/values-gl/strings.xml +++ b/packages/InputDevices/res/values-gl/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbio (cirílico)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanés"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-gu/strings.xml b/packages/InputDevices/res/values-gu/strings.xml index a5a522ecbf31..60965dcab4b0 100644 --- a/packages/InputDevices/res/values-gu/strings.xml +++ b/packages/InputDevices/res/values-gu/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"સર્બિયન (સિરિલિક)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"મોંટેનેગ્રીન (સિરિલિક)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"રોમાનિયન"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"અંગ્રેજી (ભારત)"</string> </resources> diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml index ad9c980d00a9..175197905af1 100644 --- a/packages/InputDevices/res/values-hi/strings.xml +++ b/packages/InputDevices/res/values-hi/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"सर्बियन (सिरिलिक)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"मोंटेनेग्रिन (सिरिलिक)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"रोमेनियन"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml index b7e8ee4cad17..746eb0309282 100644 --- a/packages/InputDevices/res/values-hr/strings.xml +++ b/packages/InputDevices/res/values-hr/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srpski (ćirilica)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"crnogorski (ćirilica)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunjski"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"engleski (Indija)"</string> </resources> diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml index 756cc0846ff2..c83ba841653b 100644 --- a/packages/InputDevices/res/values-hu/strings.xml +++ b/packages/InputDevices/res/values-hu/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"szerb (cirill betűs)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"montenegrói (cirill betűs)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"román"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-hy/strings.xml b/packages/InputDevices/res/values-hy/strings.xml index eced5cdbde2d..718f8d1fede1 100644 --- a/packages/InputDevices/res/values-hy/strings.xml +++ b/packages/InputDevices/res/values-hy/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"սերբերեն (կյուրեղատառ)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"չեռնոգորերեն (կյուրեղատառ)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Ռումիներեն"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml index e871d1947fab..ba2e5bd38b9a 100644 --- a/packages/InputDevices/res/values-in/strings.xml +++ b/packages/InputDevices/res/values-in/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbia (Sirilik)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegro (Sirilik)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumania"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-is/strings.xml b/packages/InputDevices/res/values-is/strings.xml index ec5d98b24ec6..842119d0ee54 100644 --- a/packages/InputDevices/res/values-is/strings.xml +++ b/packages/InputDevices/res/values-is/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbneska (kyrillískt)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Svartfellska (kyrillískt)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rúmenska"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml index 06ceb7affeeb..f7f76e0a64be 100644 --- a/packages/InputDevices/res/values-it/strings.xml +++ b/packages/InputDevices/res/values-it/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbo (cirillico)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirillico)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumeno"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml index 85f9656dedde..0df5d20e351b 100644 --- a/packages/InputDevices/res/values-iw/strings.xml +++ b/packages/InputDevices/res/values-iw/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"סרבית (אותיות קיריליות)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"מונטנגרית (אותיות קיריליות)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"רומנית"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml index 4c6de705565e..41c244ca310d 100644 --- a/packages/InputDevices/res/values-ja/strings.xml +++ b/packages/InputDevices/res/values-ja/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"セルビア語(キリル)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"モンテネグロ語(キリル)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ルーマニア語"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"英語(インド)"</string> </resources> diff --git a/packages/InputDevices/res/values-ka/strings.xml b/packages/InputDevices/res/values-ka/strings.xml index 7232c1a7db9c..0a9ba3f4a58c 100644 --- a/packages/InputDevices/res/values-ka/strings.xml +++ b/packages/InputDevices/res/values-ka/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"სერბული (კირილიცა)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"მონტენეგრული (კირილიცა)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"რუმინული"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"ინგლისური (ინდოეთი)"</string> </resources> diff --git a/packages/InputDevices/res/values-kk/strings.xml b/packages/InputDevices/res/values-kk/strings.xml index 278c868d76d4..60ad838930a7 100644 --- a/packages/InputDevices/res/values-kk/strings.xml +++ b/packages/InputDevices/res/values-kk/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербия (кириллица)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Черногория (кириллица)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румын"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-km/strings.xml b/packages/InputDevices/res/values-km/strings.xml index 2eaeaa7f03ac..936c925ab89b 100644 --- a/packages/InputDevices/res/values-km/strings.xml +++ b/packages/InputDevices/res/values-km/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"សែប៊ី (ស៊ីរីលីក)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ម៉ុងតេណេហ្គ្រោ (ស៊ីរីលីក)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"រ៉ូម៉ានី"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-kn/strings.xml b/packages/InputDevices/res/values-kn/strings.xml index 8039039ca0fc..24539519f155 100644 --- a/packages/InputDevices/res/values-kn/strings.xml +++ b/packages/InputDevices/res/values-kn/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ಸೆರ್ಬಿಯನ್ (ಸಿರಿಲಿಕ್)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ಮೊಂಟೆನೆಗ್ರಿನ್ (ಸಿರಿಲಿಕ್)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ರೊಮೇನಿಯನ್"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml index de1bb3d5dbe6..07975a4f904d 100644 --- a/packages/InputDevices/res/values-ko/strings.xml +++ b/packages/InputDevices/res/values-ko/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"세르비아어(키릴 자모)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"몬테네그로어(키릴)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"루마니아어"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"영어(인도)"</string> </resources> diff --git a/packages/InputDevices/res/values-ky/strings.xml b/packages/InputDevices/res/values-ky/strings.xml index 47bf7b73405f..f6d018ec7f01 100644 --- a/packages/InputDevices/res/values-ky/strings.xml +++ b/packages/InputDevices/res/values-ky/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербче (Кирилл)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Черногориялыкча (Кирилл)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румынча"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-lo/strings.xml b/packages/InputDevices/res/values-lo/strings.xml index 6a35f23b4f9e..61f8f71cf073 100644 --- a/packages/InputDevices/res/values-lo/strings.xml +++ b/packages/InputDevices/res/values-lo/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ເຊີບຽນ (ຊີຣິວລິກ)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ມອນເທເນກຣິນ (ຊີຣິວລິກ)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ໂຣມານຽນ"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml index 4bf9223099d1..fc9941f53d9b 100644 --- a/packages/InputDevices/res/values-lt/strings.xml +++ b/packages/InputDevices/res/values-lt/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbų (kirilica)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Juodkalniečių (kirilica)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumunų"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Anglų k. (Indija)"</string> </resources> diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml index 90d690ca10b7..cc2c94c1811f 100644 --- a/packages/InputDevices/res/values-lv/strings.xml +++ b/packages/InputDevices/res/values-lv/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbu (kirilica)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Melnkalniešu (kirilica)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumāņu"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-mk/strings.xml b/packages/InputDevices/res/values-mk/strings.xml index 4c80a80af8a3..60981d65a484 100644 --- a/packages/InputDevices/res/values-mk/strings.xml +++ b/packages/InputDevices/res/values-mk/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"српски (кирилица)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"црногорски (кирилица)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"романски"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ml/strings.xml b/packages/InputDevices/res/values-ml/strings.xml index 41ea10f22aa3..8064c74c7b61 100644 --- a/packages/InputDevices/res/values-ml/strings.xml +++ b/packages/InputDevices/res/values-ml/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"സെർബിയൻ (സിറിലിക്)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"മോണ്ടിനെഗ്രിൻ (സിറിലിക്)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"റൊമേനിയൻ"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-mn/strings.xml b/packages/InputDevices/res/values-mn/strings.xml index 056e728f4687..547ce49fc658 100644 --- a/packages/InputDevices/res/values-mn/strings.xml +++ b/packages/InputDevices/res/values-mn/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Серби (кирилл)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Монтенегро (кирилл)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румын"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-mr/strings.xml b/packages/InputDevices/res/values-mr/strings.xml index fe032fe3999e..25bdfab5a584 100644 --- a/packages/InputDevices/res/values-mr/strings.xml +++ b/packages/InputDevices/res/values-mr/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"सर्बियन (सिरिलिक)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"मॉन्टेनेग्रिन (सिरिलिक)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"रोमानियन"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ms/strings.xml b/packages/InputDevices/res/values-ms/strings.xml index f9d18a1055ef..b6e36ab6ef0c 100644 --- a/packages/InputDevices/res/values-ms/strings.xml +++ b/packages/InputDevices/res/values-ms/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbia (Cyril)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyril)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Bahasa Romania"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Bahasa Inggeris (India)"</string> </resources> diff --git a/packages/InputDevices/res/values-my/strings.xml b/packages/InputDevices/res/values-my/strings.xml index 47498e079981..4ef5aab9bec6 100644 --- a/packages/InputDevices/res/values-my/strings.xml +++ b/packages/InputDevices/res/values-my/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ဆားဘီးယား (စီရီလစ်)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"မွန်တီနီဂရင်း (စီရီလစ်)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ရိုမေးနီးယား"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml index 954462c783ff..837e24645e63 100644 --- a/packages/InputDevices/res/values-nb/strings.xml +++ b/packages/InputDevices/res/values-nb/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisk (kyrillisk)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrisk (kyrillisk)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumensk"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ne/strings.xml b/packages/InputDevices/res/values-ne/strings.xml index e2804d4a89b5..0ab1ea6db71f 100644 --- a/packages/InputDevices/res/values-ne/strings.xml +++ b/packages/InputDevices/res/values-ne/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"सर्बियाली (सिरिलिक)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"मोन्टेनिग्रिन (सिरिलिक)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"रोमानियाली"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml index 67f78bad4158..5c175fb97fff 100644 --- a/packages/InputDevices/res/values-nl/strings.xml +++ b/packages/InputDevices/res/values-nl/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Servisch (Cyrillisch)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrijns (Cyrillisch)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Roemeens"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Engels (India)"</string> </resources> diff --git a/packages/InputDevices/res/values-or/strings.xml b/packages/InputDevices/res/values-or/strings.xml index c6e020cae6d0..97f9088ceb33 100644 --- a/packages/InputDevices/res/values-or/strings.xml +++ b/packages/InputDevices/res/values-or/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ସର୍ବିଆନ (ସିରିଲିକ)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ମଣ୍ଟେନେଗ୍ରିନ (ସିରିଲିକ)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ରୋମାନିଆନ"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-pa/strings.xml b/packages/InputDevices/res/values-pa/strings.xml index 29c3b7d14bb2..343418e5cd5f 100644 --- a/packages/InputDevices/res/values-pa/strings.xml +++ b/packages/InputDevices/res/values-pa/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"ਸਰਬੀਆਈ (ਸਿਰਿਲਿਕ)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"ਮਾਂਟੇਨੀਗਰਿਨ (ਸਿਰਿਲਿਕ)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ਰੋਮਾਨੀਆਈ"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"ਅੰਗਰੇਜ਼ੀ (ਭਾਰਤ)"</string> </resources> diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml index 8ce00d3947b8..0fd962b46e9b 100644 --- a/packages/InputDevices/res/values-pl/strings.xml +++ b/packages/InputDevices/res/values-pl/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"serbski (cyrylica)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"czarnogórski (cyrylica)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumuński"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml index 3b1fc9b888d9..e649b58381f0 100644 --- a/packages/InputDevices/res/values-pt-rBR/strings.xml +++ b/packages/InputDevices/res/values-pt-rBR/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sérvio (cirílico)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romeno"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Inglês (Índia)"</string> </resources> diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml index 163108d94367..cd0a04621a9a 100644 --- a/packages/InputDevices/res/values-pt-rPT/strings.xml +++ b/packages/InputDevices/res/values-pt-rPT/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sérvio (cirílico)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romeno"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Inglês (Índia)"</string> </resources> diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml index 3b1fc9b888d9..e649b58381f0 100644 --- a/packages/InputDevices/res/values-pt/strings.xml +++ b/packages/InputDevices/res/values-pt/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sérvio (cirílico)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrino (cirílico)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romeno"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Inglês (Índia)"</string> </resources> diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml index 78c99ce4e20e..169378de0e88 100644 --- a/packages/InputDevices/res/values-ro/strings.xml +++ b/packages/InputDevices/res/values-ro/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sârbă (caractere chirilice)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Muntenegreană (Chirilică)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Română"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml index 183b00e203b4..2d5a6b0f5106 100644 --- a/packages/InputDevices/res/values-ru/strings.xml +++ b/packages/InputDevices/res/values-ru/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербский (кириллица)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Черногорский (кириллица)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румынский"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"Английский (Индия)"</string> </resources> diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml index 78d10101358e..ba27136317d9 100644 --- a/packages/InputDevices/res/values-si/strings.xml +++ b/packages/InputDevices/res/values-si/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"සර්බියානු (සිරිලික්)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"මොන්ටෙනේග්රීන් (සිරිලික්)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"රුමේනියානු"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml index c269085202b6..8ae45be04ca4 100644 --- a/packages/InputDevices/res/values-sk/strings.xml +++ b/packages/InputDevices/res/values-sk/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srbčina (cyrilika)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"čiernohorčina (cyrilika)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumunčina"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"angličtina (India)"</string> </resources> diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml index d2e9fd182d21..ced6ab1b96b5 100644 --- a/packages/InputDevices/res/values-sl/strings.xml +++ b/packages/InputDevices/res/values-sl/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"srbščina (cirilica)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"črnogorščina (cirilica)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"romunščina"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"angleščina (Indija)"</string> </resources> diff --git a/packages/InputDevices/res/values-sq/strings.xml b/packages/InputDevices/res/values-sq/strings.xml index 066129e87769..c77de92f9cdf 100644 --- a/packages/InputDevices/res/values-sq/strings.xml +++ b/packages/InputDevices/res/values-sq/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbisht (cirilike)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Malazisht (cirilike)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumanisht"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml index e4fed039668f..0c0748ddc94a 100644 --- a/packages/InputDevices/res/values-sr/strings.xml +++ b/packages/InputDevices/res/values-sr/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"српски (ћирилица)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"црногорски (ћирилица)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"румунски"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"енглески (Индија)"</string> </resources> diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml index 4eaf856adde9..5701d015977e 100644 --- a/packages/InputDevices/res/values-sv/strings.xml +++ b/packages/InputDevices/res/values-sv/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"serbiska (kyrilliskt)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"montenegrinska (kyrilliskt)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"rumänska"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"engelska (Indien)"</string> </resources> diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml index 30b52b25468c..d9ac91f860f1 100644 --- a/packages/InputDevices/res/values-sw/strings.xml +++ b/packages/InputDevices/res/values-sw/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Kiserbia (Kisiriliki)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Kimontenegri (Kisiriliki)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Kiromania"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ta/strings.xml b/packages/InputDevices/res/values-ta/strings.xml index d60084cd62f7..fc91d696f575 100644 --- a/packages/InputDevices/res/values-ta/strings.xml +++ b/packages/InputDevices/res/values-ta/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"செர்பியன் (சிரிலிக்)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"மாண்டினெக்ரன் (சிரிலிக்)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"ரோமானியன்"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-te/strings.xml b/packages/InputDevices/res/values-te/strings.xml index 2f40442de757..f164736bf7a6 100644 --- a/packages/InputDevices/res/values-te/strings.xml +++ b/packages/InputDevices/res/values-te/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"సెర్బియన్ (సిరిలిక్)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"మాంటెనెగ్రిన్ (సిరిలిక్)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"రొమేనియన్"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"ఇంగ్లీష్ (భారతదేశం)"</string> </resources> diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml index ae10f0409760..1538fdbaf33e 100644 --- a/packages/InputDevices/res/values-th/strings.xml +++ b/packages/InputDevices/res/values-th/strings.xml @@ -57,4 +57,5 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"เซอร์เบีย (ซีริลลิก)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"มอนเตเนโกร (ซีริลลิก)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"โรมาเนีย"</string> + <string name="keyboard_layout_english_india" msgid="7962353311188603367">"อังกฤษ (อินเดีย)"</string> </resources> diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml index dc0d1f52fe8f..ea815d5cbd8d 100644 --- a/packages/InputDevices/res/values-tl/strings.xml +++ b/packages/InputDevices/res/values-tl/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Romanian"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml index 2e7084d43cdd..3a40c84c71d3 100644 --- a/packages/InputDevices/res/values-tr/strings.xml +++ b/packages/InputDevices/res/values-tr/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Sırpça (Kiril)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Karadağca (Kiril)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumence"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml index 01d34e362c7f..0e0d562e0b73 100644 --- a/packages/InputDevices/res/values-uk/strings.xml +++ b/packages/InputDevices/res/values-uk/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Сербська (кирилиця)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Чорногорська (кирилиця)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Румунська"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-ur/strings.xml b/packages/InputDevices/res/values-ur/strings.xml index 94cd329ff442..44721b8eb7ac 100644 --- a/packages/InputDevices/res/values-ur/strings.xml +++ b/packages/InputDevices/res/values-ur/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"سربیائی (سیریلک)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"مونٹے نیگریائی (سیریلک)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"رومانیائی"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml index e63fc09b8d00..776c1c71a256 100644 --- a/packages/InputDevices/res/values-uz/strings.xml +++ b/packages/InputDevices/res/values-uz/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serb (kirill)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Chernogor (kirill)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Rumin"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml index 8384c3ec0652..1fcba4269748 100644 --- a/packages/InputDevices/res/values-vi/strings.xml +++ b/packages/InputDevices/res/values-vi/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Tiếng Serbia (Chữ Kirin)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Tiếng Montenegro (Chữ Kirin)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"Tiếng Romania"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml index e3a8af367d70..cb7f6cb895dc 100644 --- a/packages/InputDevices/res/values-zh-rCN/strings.xml +++ b/packages/InputDevices/res/values-zh-rCN/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"塞尔维亚语(西里尔字母)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"黑山语(西里尔字母)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"罗马尼亚语"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml index 56681b8d3ece..c718760a618e 100644 --- a/packages/InputDevices/res/values-zh-rHK/strings.xml +++ b/packages/InputDevices/res/values-zh-rHK/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"塞爾維亞文 (西里爾字母)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"蒙特內哥羅文 (西里爾字母)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"羅馬尼亞文"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml index 60c085bb2bac..68cf9b0e6b20 100644 --- a/packages/InputDevices/res/values-zh-rTW/strings.xml +++ b/packages/InputDevices/res/values-zh-rTW/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"塞爾維亞文 (西里爾字母)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"蒙特內哥羅文 (西里爾字母)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"羅馬尼亞文"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml index 66973333fa75..4ae9e47fdf91 100644 --- a/packages/InputDevices/res/values-zu/strings.xml +++ b/packages/InputDevices/res/values-zu/strings.xml @@ -57,4 +57,6 @@ <string name="keyboard_layout_serbian_cyrillic" msgid="7013541044323542196">"Serbian (Cyrillic)"</string> <string name="keyboard_layout_montenegrin_cyrillic" msgid="2391253952894077421">"Montenegrin (Cyrillic)"</string> <string name="keyboard_layout_romanian" msgid="8698989892731726903">"IsiRomanian"</string> + <!-- no translation found for keyboard_layout_english_india (7962353311188603367) --> + <skip /> </resources> diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java index a3b06e8c71fc..5590ca725327 100644 --- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java @@ -23,6 +23,7 @@ import android.app.backup.BackupAnnotations; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupManagerMonitor; +import android.app.backup.BackupRestoreEventLogger; import android.app.backup.BackupRestoreEventLogger.DataTypeResult; import android.app.backup.BackupTransport; import android.app.backup.RestoreDescription; @@ -38,6 +39,7 @@ import android.system.Os; import android.system.StructStat; import android.util.ArrayMap; import android.util.Base64; +import android.util.Dumpable; import android.util.Log; import com.android.tools.r8.keepanno.annotations.KeepTarget; @@ -51,6 +53,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -59,11 +63,14 @@ import java.util.List; /** * Backup transport for stashing stuff into a known location on disk, and * later restoring from there. For testing only. + * + * <p>Note: the quickest way to build and sync this class is: + * {@code m LocalTransport && adb install $OUT/system/priv-app/LocalTransport/LocalTransport.apk} */ public class LocalTransport extends BackupTransport { - private static final String TAG = "LocalTransport"; - private static final boolean DEBUG = false; + static final String TAG = "LocalTransport"; + static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE); private static final String TRANSPORT_DIR_NAME = "com.android.localtransport.LocalTransport"; @@ -124,6 +131,8 @@ public class LocalTransport extends BackupTransport { } public LocalTransport(Context context, LocalTransportParameters parameters) { + Log.i(TAG, "Creating LocalTransport for user " + context.getUserId() + + " (DEBUG=" + DEBUG + ")"); mContext = context; mParameters = parameters; makeDataDirs(); @@ -910,36 +919,69 @@ public class LocalTransport extends BackupTransport { return mMonitor; } - private class TestBackupManagerMonitor extends BackupManagerMonitor { + private class TestBackupManagerMonitor extends BackupManagerMonitor implements Dumpable { + + private final List<DataTypeResult> mReceivedResults = new ArrayList<>(); + private int mNumberReceivedEvents; + @Override public void onEvent(Bundle event) { - if (event == null || !mParameters.logAgentResults()) { + if (event == null) { + if (DEBUG) { + Log.w(TAG, "onEvent() called with null"); + } return; } - - if (event.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID) - == BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS) { + int eventId = event.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID); + if (eventId != BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS) { + if (DEBUG) Log.v(TAG, "ignoring event with id " + eventId); + return; + } + mNumberReceivedEvents++; + boolean logResults = mParameters.logAgentResults(); + ArrayList<DataTypeResult> results = event.getParcelableArrayList( + BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS, + DataTypeResult.class); + int size = results.size(); + if (size == 0) { + if (logResults) { + Log.i(TAG, "no agent_logging_results on event #" + mNumberReceivedEvents); + } + return; + } + if (logResults) { Log.i(TAG, "agent_logging_results {"); - ArrayList<DataTypeResult> results = event.getParcelableArrayList( - BackupManagerMonitor.EXTRA_LOG_AGENT_LOGGING_RESULTS, - DataTypeResult.class); - for (DataTypeResult result : results) { - Log.i(TAG, "\tdataType: " + result.getDataType()); - Log.i(TAG, "\tsuccessCount: " + result.getSuccessCount()); - Log.i(TAG, "\tfailCount: " + result.getFailCount()); - Log.i(TAG, "\tmetadataHash: " + Arrays.toString(result.getMetadataHash())); - - if (!result.getErrors().isEmpty()) { - Log.i(TAG, "\terrors {"); - for (String error : result.getErrors().keySet()) { - Log.i(TAG, "\t\t" + error + ": " + result.getErrors().get(error)); - } - Log.i(TAG, "\t}"); - } - - Log.i(TAG, "}"); + } + for (int i = 0; i < size; i++) { + var result = results.get(i); + mReceivedResults.add(result); + if (logResults) { + Log.i(TAG, "\t" + BackupRestoreEventLogger.toString(result)); } } + if (logResults) { + Log.i(TAG, "}"); + } + } + + @Override + public void dump(PrintWriter pw, String[] args) { + pw.println("TestBackupManagerMonitor"); + pw.printf("%d events received", mNumberReceivedEvents); + if (mNumberReceivedEvents == 0) { + pw.println(); + return; + } + int size = mReceivedResults.size(); + if (size == 0) { + pw.println("; no results on them"); + return; + } + pw.printf("; %d results on them:\n", size); + for (int i = 0; i < size; i++) { + DataTypeResult result = mReceivedResults.get(i); + pw.printf(" #%d: %s\n", i, BackupRestoreEventLogger.toString(result)); + } } } @@ -953,4 +995,60 @@ public class LocalTransport extends BackupTransport { } return mParameters.noRestrictedModePackages(); } + + @Override + public String toString() { + try { + try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) { + dump(pw, /* args= */ null); + pw.flush(); + return sw.toString(); + } + } catch (IOException e) { + // Shouldn't happen... + Log.e(TAG, "toString(): failed to dump", e); + return super.toString(); + } + } + + void dump(PrintWriter pw, String[] args) { + pw.printf("mDataDir: %s\n", mDataDir); + pw.printf("mCurrentSetDir: %s\n", mCurrentSetDir); + pw.printf("mCurrentSetIncrementalDir: %s\n", mCurrentSetIncrementalDir); + pw.printf("mCurrentSetFullDir: %s\n", mCurrentSetFullDir); + + pw.printf("mRestorePackages: %s\n", Arrays.toString(mRestorePackages)); + pw.printf("mRestorePackage: %d\n", mRestorePackage); + pw.printf("mRestoreType: %d\n", mRestoreType); + pw.printf("mRestoreSetDir: %s\n", mRestoreSetDir); + pw.printf("mRestoreSetIncrementalDir: %s\n", mRestoreSetIncrementalDir); + pw.printf("mRestoreSetFullDir: %s\n", mRestoreSetFullDir); + + pw.printf("mFullTargetPackage: %s\n", mFullTargetPackage); + pw.printf("mSocket: %s\n", mSocket); + pw.printf("mSocketInputStream: %s\n", mSocketInputStream); + pw.printf("mFullBackupOutputStream: %s\n", mFullBackupOutputStream); + dumpByteArray(pw, "mFullBackupBuffer", mFullBackupBuffer); + pw.printf("mFullBackupSize: %d\n", mFullBackupSize); + + pw.printf("mCurFullRestoreStream: %s\n", mCurFullRestoreStream); + dumpByteArray(pw, "mFullRestoreBuffer", mFullRestoreBuffer); + if (mParameters == null) { + pw.println("No LocalTransportParameters"); + } else { + pw.println(mParameters); + } + if (mMonitor instanceof Dumpable) { + ((Dumpable) mMonitor).dump(pw, args); + } + + pw.printf("currentDestinationString(): %s\n", currentDestinationString()); + pw.printf("dataManagementIntent(): %s\n", dataManagementIntent()); + pw.printf("dataManagementIntentLabel(): %s\n", dataManagementIntentLabel()); + pw.printf("transportDirName(): %s\n", transportDirName()); + } + + private void dumpByteArray(PrintWriter pw, String name, byte[] array) { + pw.printf("%s size: %d\n", name, (array == null ? 0 : array.length)); + } } diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java index c980913f80c6..c7cfc5b4d304 100644 --- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java @@ -16,11 +16,15 @@ package com.android.localtransport; +import static com.android.localtransport.LocalTransport.DEBUG; +import static com.android.localtransport.LocalTransport.TAG; + import android.content.ContentResolver; import android.os.Handler; import android.provider.Settings; import android.util.KeyValueListParser; import android.util.KeyValueSettingObserver; +import android.util.Log; import java.util.Arrays; import java.util.List; @@ -76,15 +80,30 @@ public class LocalTransportParameters extends KeyValueSettingObserver { } public String getSettingValue(ContentResolver resolver) { - return Settings.Secure.getString(resolver, SETTING); + String value = Settings.Secure.getString(resolver, SETTING); + if (DEBUG) { + Log.d(TAG, "LocalTransportParameters.getSettingValue(): returning " + value); + } + return value; } public void update(KeyValueListParser parser) { - mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false); - mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false); - mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, false); - mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, false); - mLogAgentResults = parser.getBoolean(KEY_LOG_AGENT_RESULTS, /* def */ false); + mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, /* def= */ false); + mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, /* def= */ false); + mIsDeviceTransfer = parser.getBoolean(KEY_IS_DEVICE_TRANSFER, /* def= */ false); + mIsEncrypted = parser.getBoolean(KEY_IS_ENCRYPTED, /* def= */ false); + mLogAgentResults = parser.getBoolean(KEY_LOG_AGENT_RESULTS, /* def= */ false); mNoRestrictedModePackages = parser.getString(KEY_NO_RESTRICTED_MODE_PACKAGES, /* def */ ""); } + + @Override + public String toString() { + return "LocalTransportParameters[mFakeEncryptionFlag=" + mFakeEncryptionFlag + + ", mIsNonIncrementalOnly=" + mIsNonIncrementalOnly + + ", mIsDeviceTransfer=" + mIsDeviceTransfer + + ", mIsEncrypted=" + mIsEncrypted + + ", mLogAgentResults=" + mLogAgentResults + + ", noRestrictedModePackages()=" + noRestrictedModePackages() + + "]"; + } } diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java index ac4f418b68f6..2f6c57a7b207 100644 --- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java +++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportService.java @@ -16,15 +16,28 @@ package com.android.localtransport; +import static com.android.localtransport.LocalTransport.DEBUG; +import static com.android.localtransport.LocalTransport.TAG; + +import android.annotation.Nullable; import android.app.Service; import android.content.Intent; import android.os.IBinder; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.PrintWriter; public class LocalTransportService extends Service { - private static LocalTransport sTransport = null; + + @Nullable + private static LocalTransport sTransport; @Override public void onCreate() { + if (DEBUG) { + Log.d(TAG, "LocalTransportService.onCreate()"); + } if (sTransport == null) { LocalTransportParameters parameters = new LocalTransportParameters(getMainThreadHandler(), getContentResolver()); @@ -35,11 +48,27 @@ public class LocalTransportService extends Service { @Override public void onDestroy() { + if (DEBUG) { + Log.d(TAG, "LocalTransportService.onDestroy()"); + } sTransport.getParameters().stop(); } @Override public IBinder onBind(Intent intent) { + if (DEBUG) { + Log.d(TAG, "LocalTransportService.onBind(" + intent + "): parameters=" + + sTransport.getParameters()); + } return sTransport.getBinder(); } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (sTransport == null) { + pw.println("No sTransport"); + return; + } + sTransport.dump(pw, args); + } } diff --git a/packages/NeuralNetworks/OWNERS b/packages/NeuralNetworks/OWNERS index 6b391503b5c4..bf3c8fe1550f 100644 --- a/packages/NeuralNetworks/OWNERS +++ b/packages/NeuralNetworks/OWNERS @@ -1,5 +1,4 @@ # Bug component: 195575 sandeepbandaru@google.com -shivanker@google.com -shiqing@google.com
\ No newline at end of file +shiqing@google.com diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp index a30c0c3c6d4c..8b1828c5f41f 100644 --- a/packages/PackageInstaller/Android.bp +++ b/packages/PackageInstaller/Android.bp @@ -47,19 +47,21 @@ android_app { sdk_version: "system_current", rename_resources_package: false, static_libs: [ - "androidx.leanback_leanback", + "android.content.pm.flags-aconfig-java", + "android.multiuser.flags-aconfig-java", + "android.os.flags-aconfig-java", "androidx.annotation_annotation", "androidx.fragment_fragment", - "androidx.lifecycle_lifecycle-livedata", + "androidx.leanback_leanback", "androidx.lifecycle_lifecycle-extensions", - "android.content.pm.flags-aconfig-java", - "android.os.flags-aconfig-java", - "android.multiuser.flags-aconfig-java", + "androidx.lifecycle_lifecycle-livedata", + "kotlin-parcelize-runtime", ], lint: { error_checks: ["Recycle"], }, + kotlin_plugins: ["kotlin-parcelize-compiler-plugin"], } android_app { @@ -79,19 +81,22 @@ android_app { overrides: ["PackageInstaller"], static_libs: [ - "androidx.leanback_leanback", - "androidx.fragment_fragment", - "androidx.lifecycle_lifecycle-livedata", - "androidx.lifecycle_lifecycle-extensions", "android.content.pm.flags-aconfig-java", - "android.os.flags-aconfig-java", "android.multiuser.flags-aconfig-java", + "android.os.flags-aconfig-java", + "androidx.annotation_annotation", + "androidx.fragment_fragment", + "androidx.leanback_leanback", + "androidx.lifecycle_lifecycle-extensions", + "androidx.lifecycle_lifecycle-livedata", + "kotlin-parcelize-runtime", ], aaptflags: ["--product tablet"], lint: { error_checks: ["Recycle"], }, + kotlin_plugins: ["kotlin-parcelize-compiler-plugin"], } android_app { @@ -111,18 +116,20 @@ android_app { overrides: ["PackageInstaller"], static_libs: [ - "androidx.leanback_leanback", + "android.content.pm.flags-aconfig-java", + "android.multiuser.flags-aconfig-java", + "android.os.flags-aconfig-java", "androidx.annotation_annotation", "androidx.fragment_fragment", - "androidx.lifecycle_lifecycle-livedata", + "androidx.leanback_leanback", "androidx.lifecycle_lifecycle-extensions", - "android.content.pm.flags-aconfig-java", - "android.os.flags-aconfig-java", - "android.multiuser.flags-aconfig-java", + "androidx.lifecycle_lifecycle-livedata", + "kotlin-parcelize-runtime", ], aaptflags: ["--product tv"], lint: { error_checks: ["Recycle"], }, + kotlin_plugins: ["kotlin-parcelize-compiler-plugin"], } diff --git a/packages/PackageInstaller/res/values-or/strings.xml b/packages/PackageInstaller/res/values-or/strings.xml index b99bf1a3c85d..dab240163577 100644 --- a/packages/PackageInstaller/res/values-or/strings.xml +++ b/packages/PackageInstaller/res/values-or/strings.xml @@ -58,7 +58,7 @@ <string name="uninstall_application_title" msgid="4045420072401428123">"ଆପ୍କୁ ଅନଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string> <string name="uninstall_update_title" msgid="824411791011583031">"ଅପଡେଟ୍ ଅନଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string> <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> ହେଉଛି ନିମ୍ନ ଆପ୍ର ଏକ ଅଂଶ।"</string> - <string name="uninstall_application_text" msgid="3816830743706143980">"ଆପଣ ଏହି ଆପ୍ ଅନଇନଷ୍ଟଲ୍ କରିବାକୁ ଚାହାଁନ୍ତି କି?"</string> + <string name="uninstall_application_text" msgid="3816830743706143980">"ଆପଣ ଏହି ଆପ ଅନଇନଷ୍ଟଲ କରିବାକୁ ଚାହାଁନ୍ତି କି?"</string> <string name="archive_application_text" msgid="8482325710714386348">"ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଡାଟା ସେଭ ହୋଇଯିବ"</string> <string name="archive_application_text_all_users" msgid="3151229641681672580">"ସମସ୍ତ ୟୁଜରଙ୍କ ପାଇଁ ଏହି ଆପକୁ ଆର୍କାଇଭ କରିବେ? ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଡାଟା ସେଭ ହୋଇଯିବ"</string> <string name="archive_application_text_current_user_work_profile" msgid="1450487362134779752">"ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲରେ ଏହି ଆପକୁ ଆର୍କାଇଭ କରିବେ? ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ଡାଟା ସେଭ ହୋଇଯିବ"</string> diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt index 8de8fbb3e688..a8dad096e4b0 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt @@ -18,8 +18,8 @@ package com.android.packageinstaller.v2.model import android.app.Activity import android.content.Intent -import android.content.pm.PackageManager import android.content.pm.PackageInstaller +import android.content.pm.PackageManager import android.graphics.drawable.Drawable sealed class InstallStage(val stageCode: Int) { @@ -42,7 +42,7 @@ class InstallReady : InstallStage(STAGE_READY) data class InstallUserActionRequired( val actionReason: Int, - private val appSnippet: PackageUtil.AppSnippet? = null, + val appSnippet: PackageUtil.AppSnippet? = null, val isAppUpdating: Boolean = false, /** * This holds either a package name or the app label of the install source. @@ -63,7 +63,7 @@ data class InstallUserActionRequired( } } -data class InstallInstalling(private val appSnippet: PackageUtil.AppSnippet) : +data class InstallInstalling(val appSnippet: PackageUtil.AppSnippet) : InstallStage(STAGE_INSTALLING) { val appIcon: Drawable? @@ -74,7 +74,7 @@ data class InstallInstalling(private val appSnippet: PackageUtil.AppSnippet) : } data class InstallSuccess( - private val appSnippet: PackageUtil.AppSnippet, + val appSnippet: PackageUtil.AppSnippet, val shouldReturnResult: Boolean = false, /** * @@ -95,7 +95,7 @@ data class InstallSuccess( } data class InstallFailed( - private val appSnippet: PackageUtil.AppSnippet? = null, + val appSnippet: PackageUtil.AppSnippet? = null, val legacyCode: Int, val statusCode: Int, val message: String? = null, diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt index 828a95fcbb01..e8477ef261a8 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt @@ -17,21 +17,32 @@ package com.android.packageinstaller.v2.model import android.Manifest +import android.annotation.SuppressLint +import android.app.ActivityManager import android.content.Context import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageInstaller import android.content.pm.PackageManager import android.content.res.Resources +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.net.Uri import android.os.Build +import android.os.Parcel +import android.os.Parcelable import android.os.Process import android.os.UserHandle import android.os.UserManager import android.util.Log +import com.android.packageinstaller.v2.model.PackageUtil.getAppSnippet +import java.io.ByteArrayOutputStream import java.io.File +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize object PackageUtil { private val LOG_TAG = InstallRepository::class.java.simpleName @@ -39,6 +50,24 @@ object PackageUtil { private const val SPLIT_BASE_APK_SUFFIX = "base.apk" const val localLogv = false + const val ARGS_ABORT_REASON: String = "abort_reason" + const val ARGS_ACTION_REASON: String = "action_reason" + const val ARGS_ACTIVITY_RESULT_CODE: String = "activity_result_code" + const val ARGS_APP_DATA_SIZE: String = "app_data_size" + const val ARGS_APP_LABEL: String = "app_label" + const val ARGS_APP_SNIPPET: String = "app_snippet" + const val ARGS_ERROR_DIALOG_TYPE: String = "error_dialog_type" + const val ARGS_IS_ARCHIVE: String = "is_archive" + const val ARGS_IS_CLONE_USER: String = "clone_user" + const val ARGS_IS_UPDATING: String = "is_updating" + const val ARGS_LEGACY_CODE: String = "legacy_code" + const val ARGS_MESSAGE: String = "message" + const val ARGS_RESULT_INTENT: String = "result_intent" + const val ARGS_SHOULD_RETURN_RESULT: String = "should_return_result" + const val ARGS_SOURCE_APP: String = "source_app" + const val ARGS_STATUS_CODE: String = "status_code" + const val ARGS_TITLE: String = "title" + /** * Determines if the UID belongs to the system downloads provider and returns the * [ApplicationInfo] of the provider @@ -238,7 +267,8 @@ object PackageUtil { context.resources, info.getAppIcon() ) else pm.defaultActivityIcon - return AppSnippet(label, icon) + val largeIconSize = getLargeIconSize(context) + return AppSnippet(label, icon, largeIconSize) } /** @@ -247,8 +277,11 @@ object PackageUtil { */ @JvmStatic fun getAppSnippet(context: Context, pkgInfo: PackageInfo): AppSnippet { + val largeIconSize = getLargeIconSize(context) return pkgInfo.applicationInfo?.let { getAppSnippet(context, it) } ?: run { - AppSnippet(pkgInfo.packageName, context.packageManager.defaultActivityIcon) + AppSnippet( + pkgInfo.packageName, context.packageManager.defaultActivityIcon, largeIconSize + ) } } @@ -261,7 +294,8 @@ object PackageUtil { val pm = context.packageManager val label = pm.getApplicationLabel(appInfo) val icon = pm.getApplicationIcon(appInfo) - return AppSnippet(label, icon) + val largeIconSize = getLargeIconSize(context) + return AppSnippet(label, icon, largeIconSize) } /** @@ -270,16 +304,24 @@ object PackageUtil { */ @JvmStatic fun getAppSnippet(context: Context, pkgInfo: PackageInfo, sourceFile: File): AppSnippet { + val largeIconSize = getLargeIconSize(context) pkgInfo.applicationInfo?.let { val appInfoFromFile = processAppInfoForFile(it, sourceFile) val label = getAppLabelFromFile(context, appInfoFromFile) val icon = getAppIconFromFile(context, appInfoFromFile) - return AppSnippet(label, icon) + return AppSnippet(label, icon, largeIconSize) } ?: run { - return AppSnippet(pkgInfo.packageName, context.packageManager.defaultActivityIcon) + return AppSnippet( + pkgInfo.packageName, context.packageManager.defaultActivityIcon, largeIconSize + ) } } + private fun getLargeIconSize(context: Context): Int { + val am = context.getSystemService<ActivityManager>(ActivityManager::class.java) + return am.launcherLargeIconSize + } + /** * Utility method to load application label * @@ -438,7 +480,69 @@ object PackageUtil { * The class to hold an incoming package's icon and label. * See [getAppSnippet] */ - data class AppSnippet(var label: CharSequence?, var icon: Drawable?) { + @Parcelize + data class AppSnippet( + var label: CharSequence?, + var icon: Drawable?, + var iconSize: Int, + ) : Parcelable { + private companion object : Parceler<AppSnippet> { + override fun AppSnippet.write(dest: Parcel, flags: Int) { + dest.writeString(label.toString()) + + val bmp = getBitmapFromDrawable(icon!!) + dest.writeBlob(getBytesFromBitmap(bmp)) + bmp.recycle() + + dest.writeInt(iconSize) + } + + @SuppressLint("UseKtx") + override fun create(parcel: Parcel): AppSnippet { + val label = parcel.readString() + + val b: ByteArray = parcel.readBlob()!! + val bmp: Bitmap? = BitmapFactory.decodeByteArray(b, 0, b.size) + val icon = BitmapDrawable(Resources.getSystem(), bmp) + + val iconSize = parcel.readInt() + + return AppSnippet(label.toString(), icon, iconSize) + } + } + + @SuppressLint("UseKtx") + private fun getBitmapFromDrawable(drawable: Drawable): Bitmap { + // Create an empty bitmap with the dimensions of our drawable + val bmp = Bitmap.createBitmap( + drawable.intrinsicWidth, + drawable.intrinsicHeight, Bitmap.Config.ARGB_8888 + ) + // Associate it with a canvas. This canvas will draw the icon on the bitmap + val canvas = Canvas(bmp) + // Draw the drawable in the canvas. The canvas will ultimately paint the drawable in the + // bitmap held within + drawable.draw(canvas) + + // Scale it down if the icon is too large + if ((bmp.getWidth() > iconSize * 2) || (bmp.getHeight() > iconSize * 2)) { + val scaledBitmap = Bitmap.createScaledBitmap(bmp, iconSize, iconSize, true) + if (scaledBitmap != bmp) { + bmp.recycle() + } + return scaledBitmap + } + return bmp + } + + private fun getBytesFromBitmap(bmp: Bitmap): ByteArray? { + var baos = ByteArrayOutputStream() + baos.use { + bmp.compress(Bitmap.CompressFormat.PNG, 100, it) + } + return baos.toByteArray() + } + override fun toString(): String { return "AppSnippet[label = $label, hasIcon = ${icon != null}]" } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt index c61a2ac9f0dd..4a8be8db9248 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt @@ -16,9 +16,6 @@ package com.android.packageinstaller.v2.ui -import android.app.Activity.RESULT_CANCELED -import android.app.Activity.RESULT_FIRST_USER -import android.app.Activity.RESULT_OK import android.app.AppOpsManager import android.content.ActivityNotFoundException import android.content.Intent @@ -67,6 +64,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { InstallLaunch::class.java.packageName + ".callingPkgName" private val LOG_TAG = InstallLaunch::class.java.simpleName private const val TAG_DIALOG = "dialog" + private const val ARGS_SAVED_INTENT = "saved_intent" } /** @@ -96,7 +94,15 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { intent.getStringExtra(EXTRA_CALLING_PKG_NAME), intent.getIntExtra(EXTRA_CALLING_PKG_UID, Process.INVALID_UID) ) - installViewModel!!.preprocessIntent(intent, info) + + var savedIntent: Intent? = null + if (savedInstanceState != null) { + savedIntent = savedInstanceState.getParcelable(ARGS_SAVED_INTENT, Intent::class.java) + } + if (!intent.filterEquals(savedIntent)) { + installViewModel!!.preprocessIntent(intent, info) + } + installViewModel!!.currentInstallStage.observe(this) { installStage: InstallStage -> onInstallStageChange(installStage) } @@ -127,9 +133,10 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { val aborted = installStage as InstallAborted when (aborted.abortReason) { InstallAborted.ABORT_REASON_DONE, - InstallAborted.ABORT_REASON_INTERNAL_ERROR -> { + InstallAborted.ABORT_REASON_INTERNAL_ERROR, + -> { if (aborted.errorDialogType == InstallAborted.DLG_PACKAGE_ERROR) { - val parseErrorDialog = ParseErrorFragment(aborted) + val parseErrorDialog = ParseErrorFragment.newInstance(aborted) showDialogInner(parseErrorDialog) } else { setResult(aborted.activityResultCode, aborted.resultIntent, true) @@ -145,12 +152,12 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { val uar = installStage as InstallUserActionRequired when (uar.actionReason) { InstallUserActionRequired.USER_ACTION_REASON_INSTALL_CONFIRMATION -> { - val actionDialog = InstallConfirmationFragment(uar) + val actionDialog = InstallConfirmationFragment.newInstance(uar) showDialogInner(actionDialog) } InstallUserActionRequired.USER_ACTION_REASON_UNKNOWN_SOURCE -> { - val externalSourceDialog = ExternalSourcesBlockedFragment(uar) + val externalSourceDialog = ExternalSourcesBlockedFragment.newInstance(uar) showDialogInner(externalSourceDialog) } @@ -163,7 +170,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { InstallStage.STAGE_INSTALLING -> { val installing = installStage as InstallInstalling - val installingDialog = InstallInstallingFragment(installing) + val installingDialog = InstallInstallingFragment.newInstance(installing) showDialogInner(installingDialog) } @@ -173,7 +180,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { val successIntent = success.resultIntent setResult(RESULT_OK, successIntent, true) } else { - val successDialog = InstallSuccessFragment(success) + val successDialog = InstallSuccessFragment.newInstance(success) showDialogInner(successDialog) } } @@ -184,7 +191,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { val failureIntent = failed.resultIntent setResult(RESULT_FIRST_USER, failureIntent, true) } else { - val failureDialog = InstallFailedFragment(failed) + val failureDialog = InstallFailedFragment.newInstance(failed) showDialogInner(failureDialog) } } @@ -236,11 +243,11 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { } return when (restriction) { UserManager.DISALLOW_INSTALL_APPS -> - SimpleErrorFragment(R.string.install_apps_user_restriction_dlg_text) + SimpleErrorFragment.newInstance(R.string.install_apps_user_restriction_dlg_text) UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY -> - SimpleErrorFragment(R.string.unknown_apps_user_restriction_dlg_text) + SimpleErrorFragment.newInstance(R.string.unknown_apps_user_restriction_dlg_text) else -> null } @@ -344,6 +351,11 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { appOpsManager!!.stopWatchingMode(listener) } + override fun onSaveInstanceState(outState: Bundle) { + outState.putParcelable(ARGS_SAVED_INTENT, intent) + super.onSaveInstanceState(outState) + } + override fun onDestroy() { super.onDestroy() while (activeUnknownSourcesListeners.isNotEmpty()) { diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt index c4ca27247575..08bc7666c3e1 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt @@ -16,7 +16,6 @@ package com.android.packageinstaller.v2.ui -import android.app.Activity import android.app.NotificationManager import android.content.Intent import android.os.Bundle @@ -51,6 +50,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { UninstallLaunch::class.java.packageName + ".callingActivityName" val LOG_TAG = UninstallLaunch::class.java.simpleName private const val TAG_DIALOG = "dialog" + private const val ARGS_SAVED_INTENT = "saved_intent" } private var uninstallViewModel: UninstallViewModel? = null @@ -76,7 +76,15 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { intent.getStringExtra(EXTRA_CALLING_ACTIVITY_NAME), intent.getIntExtra(EXTRA_CALLING_PKG_UID, Process.INVALID_UID) ) - uninstallViewModel!!.preprocessIntent(intent, callerInfo) + + var savedIntent: Intent? = null + if (savedInstanceState != null) { + savedIntent = savedInstanceState.getParcelable(ARGS_SAVED_INTENT, Intent::class.java) + } + if (!intent.filterEquals(savedIntent)) { + uninstallViewModel!!.preprocessIntent(intent, callerInfo) + } + uninstallViewModel!!.currentUninstallStage.observe(this) { uninstallStage: UninstallStage -> onUninstallStageChange(uninstallStage) } @@ -93,7 +101,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { if (aborted.abortReason == UninstallAborted.ABORT_REASON_APP_UNAVAILABLE || aborted.abortReason == UninstallAborted.ABORT_REASON_USER_NOT_ALLOWED ) { - val errorDialog = UninstallErrorFragment(aborted) + val errorDialog = UninstallErrorFragment.newInstance(aborted) showDialogInner(errorDialog) } else { setResult(aborted.activityResultCode, null, true) @@ -102,7 +110,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { UninstallStage.STAGE_USER_ACTION_REQUIRED -> { val uar = uninstallStage as UninstallUserActionRequired - val confirmationDialog = UninstallConfirmationFragment(uar) + val confirmationDialog = UninstallConfirmationFragment.newInstance(uar) showDialogInner(confirmationDialog) } @@ -112,7 +120,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { // And a fragment if the user requests a result back. Should we consolidate and // show a fragment always? val uninstalling = uninstallStage as UninstallUninstalling - val uninstallingDialog = UninstallUninstallingFragment(uninstalling) + val uninstallingDialog = UninstallUninstallingFragment.newInstance(uninstalling) showDialogInner(uninstallingDialog) } @@ -171,6 +179,11 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { Log.d(LOG_TAG, "Cancelling uninstall") } uninstallViewModel!!.cancelUninstall() - setResult(Activity.RESULT_FIRST_USER, null, true) + setResult(RESULT_FIRST_USER, null, true) + } + + override fun onSaveInstanceState(outState: Bundle) { + outState.putParcelable(ARGS_SAVED_INTENT, intent) + super.onSaveInstanceState(outState) } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java index 343a213780b3..4c69b9d20315 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java @@ -16,17 +16,25 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ACTION_REASON; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_IS_UPDATING; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_SOURCE_APP; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallUserActionRequired; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; import com.android.packageinstaller.v2.ui.InstallActionListener; /** @@ -37,14 +45,34 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { private static final String LOG_TAG = ExternalSourcesBlockedFragment.class.getSimpleName(); @NonNull - private final InstallUserActionRequired mDialogData; + private InstallUserActionRequired mDialogData; @NonNull private InstallActionListener mInstallActionListener; @NonNull private AlertDialog mDialog; - public ExternalSourcesBlockedFragment(InstallUserActionRequired dialogData) { - mDialogData = dialogData; + public ExternalSourcesBlockedFragment() { + // Required for DialogFragment + } + + /** + * Creates a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallUserActionRequired} object containing data to display + * in the dialog + * @return an instance of the fragment + */ + public static ExternalSourcesBlockedFragment newInstance( + @NonNull InstallUserActionRequired dialogData) { + Bundle args = new Bundle(); + args.putInt(ARGS_ACTION_REASON, dialogData.getActionReason()); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + args.putBoolean(ARGS_IS_UPDATING, dialogData.isAppUpdating()); + args.putString(ARGS_SOURCE_APP, dialogData.getSourceApp()); + + ExternalSourcesBlockedFragment fragment = new ExternalSourcesBlockedFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -56,6 +84,8 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); mDialog = new AlertDialog.Builder(requireContext()) .setTitle(mDialogData.getAppLabel()) @@ -96,4 +126,14 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { super.onResume(); mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); } + + private void setDialogData(Bundle args) { + int actionReason = args.getInt(ARGS_ACTION_REASON); + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + boolean isUpdating = args.getBoolean(ARGS_IS_UPDATING); + String sourceApp = args.getString(ARGS_SOURCE_APP); + + mDialogData = new InstallUserActionRequired(actionReason, appSnippet, isUpdating, + sourceApp); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java index e186590fa5e2..03768fb56bb8 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java @@ -16,6 +16,11 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ACTION_REASON; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_IS_UPDATING; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_SOURCE_APP; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; @@ -26,11 +31,14 @@ import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.view.View; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallUserActionRequired; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; import com.android.packageinstaller.v2.ui.InstallActionListener; /** @@ -39,15 +47,34 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class InstallConfirmationFragment extends DialogFragment { public static final String LOG_TAG = InstallConfirmationFragment.class.getSimpleName(); - @NonNull - private final InstallUserActionRequired mDialogData; + private InstallUserActionRequired mDialogData; @NonNull private InstallActionListener mInstallActionListener; @NonNull private AlertDialog mDialog; - public InstallConfirmationFragment(@NonNull InstallUserActionRequired dialogData) { - mDialogData = dialogData; + public InstallConfirmationFragment() { + // Required for DialogFragment + } + + /** + * Creates a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallUserActionRequired} object containing data to display + * in the dialog + * @return an instance of the fragment + */ + public static InstallConfirmationFragment newInstance( + @NonNull InstallUserActionRequired dialogData) { + Bundle args = new Bundle(); + args.putInt(ARGS_ACTION_REASON, dialogData.getActionReason()); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + args.putBoolean(ARGS_IS_UPDATING, dialogData.isAppUpdating()); + args.putString(ARGS_SOURCE_APP, dialogData.getSourceApp()); + + InstallConfirmationFragment fragment = new InstallConfirmationFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -59,6 +86,8 @@ public class InstallConfirmationFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); @@ -127,4 +156,14 @@ public class InstallConfirmationFragment extends DialogFragment { super.onResume(); mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); } + + private void setDialogData(Bundle args) { + int actionReason = args.getInt(ARGS_ACTION_REASON); + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + boolean isUpdating = args.getBoolean(ARGS_IS_UPDATING); + String sourceApp = args.getString(ARGS_SOURCE_APP); + + mDialogData = new InstallUserActionRequired(actionReason, appSnippet, isUpdating, + sourceApp); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallFailedFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallFailedFragment.java index 7c9d98dd4823..6f65441afd88 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallFailedFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallFailedFragment.java @@ -16,19 +16,30 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_LEGACY_CODE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_MESSAGE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_RESULT_INTENT; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_SHOULD_RETURN_RESULT; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_STATUS_CODE; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.PackageInstaller; import android.os.Bundle; import android.util.Log; import android.view.View; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallFailed; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; import com.android.packageinstaller.v2.ui.InstallActionListener; /** @@ -39,11 +50,32 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class InstallFailedFragment extends DialogFragment { private static final String LOG_TAG = InstallFailedFragment.class.getSimpleName(); - private final InstallFailed mDialogData; + private InstallFailed mDialogData; private InstallActionListener mInstallActionListener; - public InstallFailedFragment(InstallFailed dialogData) { - mDialogData = dialogData; + public InstallFailedFragment() { + // Required for DialogFragment + } + + /** + * Creates a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallFailed} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static InstallFailedFragment newInstance(@NonNull InstallFailed dialogData) { + Bundle args = new Bundle(); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + args.putInt(ARGS_LEGACY_CODE, dialogData.getLegacyCode()); + args.putInt(ARGS_STATUS_CODE, dialogData.getStatusCode()); + args.putString(ARGS_MESSAGE, dialogData.getMessage()); + args.putBoolean(ARGS_SHOULD_RETURN_RESULT, dialogData.getShouldReturnResult()); + args.putParcelable(ARGS_RESULT_INTENT, dialogData.getResultIntent()); + + InstallFailedFragment fragment = new InstallFailedFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -55,6 +87,8 @@ public class InstallFailedFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); AlertDialog dialog = new AlertDialog.Builder(requireContext()) @@ -105,4 +139,16 @@ public class InstallFailedFragment extends DialogFragment { super.onCancel(dialog); mInstallActionListener.onNegativeResponse(mDialogData.getStageCode()); } + + private void setDialogData(Bundle args) { + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + int legacyCode = args.getInt(ARGS_LEGACY_CODE); + int statusCode = args.getInt(ARGS_STATUS_CODE); + String message = args.getString(ARGS_MESSAGE); + boolean shouldReturnResult = args.getBoolean(ARGS_SHOULD_RETURN_RESULT); + Intent resultIntent = args.getParcelable(ARGS_RESULT_INTENT, Intent.class); + + mDialogData = new InstallFailed(appSnippet, legacyCode, statusCode, message, + shouldReturnResult, resultIntent); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallInstallingFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallInstallingFragment.java index 27210b757181..17093cf16125 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallInstallingFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallInstallingFragment.java @@ -16,17 +16,22 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; + import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; import android.view.View; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallInstalling; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; /** * Dialog to show when an install is in progress. @@ -34,16 +39,34 @@ import com.android.packageinstaller.v2.model.InstallInstalling; public class InstallInstallingFragment extends DialogFragment { private static final String LOG_TAG = InstallInstallingFragment.class.getSimpleName(); - private final InstallInstalling mDialogData; + private InstallInstalling mDialogData; private AlertDialog mDialog; - public InstallInstallingFragment(InstallInstalling dialogData) { - mDialogData = dialogData; + public InstallInstallingFragment() { + // Required for DialogFragment + } + + /** + * Creates a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallInstalling} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static InstallInstallingFragment newInstance(@NonNull InstallInstalling dialogData) { + Bundle args = new Bundle(); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + + InstallInstallingFragment fragment = new InstallInstallingFragment(); + fragment.setArguments(args); + return fragment; } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); mDialog = new AlertDialog.Builder(requireContext()) @@ -64,4 +87,9 @@ public class InstallInstallingFragment extends DialogFragment { super.onStart(); mDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setEnabled(false); } + + private void setDialogData(Bundle args) { + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + mDialogData = new InstallInstalling(appSnippet); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallSuccessFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallSuccessFragment.java index 28b5423b2d83..5696afa52622 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallSuccessFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallSuccessFragment.java @@ -16,22 +16,31 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_RESULT_INTENT; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_SHOULD_RETURN_RESULT; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallSuccess; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; import com.android.packageinstaller.v2.ui.InstallActionListener; + import java.util.List; /** @@ -41,13 +50,31 @@ import java.util.List; public class InstallSuccessFragment extends DialogFragment { private static final String LOG_TAG = InstallSuccessFragment.class.getSimpleName(); - private final InstallSuccess mDialogData; + private InstallSuccess mDialogData; private AlertDialog mDialog; private InstallActionListener mInstallActionListener; private PackageManager mPm; - public InstallSuccessFragment(InstallSuccess dialogData) { - mDialogData = dialogData; + public InstallSuccessFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallSuccess} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static InstallSuccessFragment newInstance(@NonNull InstallSuccess dialogData) { + Bundle args = new Bundle(); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + args.putBoolean(ARGS_SHOULD_RETURN_RESULT, dialogData.getShouldReturnResult()); + args.putParcelable(ARGS_RESULT_INTENT, dialogData.getResultIntent()); + + InstallSuccessFragment fragment = new InstallSuccessFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -60,6 +87,8 @@ public class InstallSuccessFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); mDialog = new AlertDialog.Builder(requireContext()) @@ -105,4 +134,12 @@ public class InstallSuccessFragment extends DialogFragment { Log.i(LOG_TAG, "Finished installing " + mDialogData.getAppLabel()); mInstallActionListener.onNegativeResponse(mDialogData.getStageCode()); } + + private void setDialogData(Bundle args) { + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + boolean shouldReturnResult = args.getBoolean(ARGS_SHOULD_RETURN_RESULT); + Intent resultIntent = args.getParcelable(ARGS_RESULT_INTENT, Intent.class); + + mDialogData = new InstallSuccess(appSnippet, shouldReturnResult, resultIntent); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ParseErrorFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ParseErrorFragment.java index cde3d8d9dd2d..6834f44a37cf 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ParseErrorFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ParseErrorFragment.java @@ -16,14 +16,23 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ABORT_REASON; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ACTIVITY_RESULT_CODE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ERROR_DIALOG_TYPE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_MESSAGE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_RESULT_INTENT; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallAborted; import com.android.packageinstaller.v2.ui.InstallActionListener; @@ -31,11 +40,31 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class ParseErrorFragment extends DialogFragment { private static final String LOG_TAG = ParseErrorFragment.class.getSimpleName(); - private final InstallAborted mDialogData; + private InstallAborted mDialogData; private InstallActionListener mInstallActionListener; - public ParseErrorFragment(InstallAborted dialogData) { - mDialogData = dialogData; + public ParseErrorFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallAborted} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static ParseErrorFragment newInstance(@NonNull InstallAborted dialogData) { + Bundle args = new Bundle(); + args.putInt(ARGS_ABORT_REASON, dialogData.getAbortReason()); + args.putString(ARGS_MESSAGE, dialogData.getMessage()); + args.putParcelable(ARGS_RESULT_INTENT, dialogData.getResultIntent()); + args.putInt(ARGS_ACTIVITY_RESULT_CODE, dialogData.getActivityResultCode()); + args.putInt(ARGS_ERROR_DIALOG_TYPE, dialogData.getErrorDialogType()); + + ParseErrorFragment fragment = new ParseErrorFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -47,6 +76,8 @@ public class ParseErrorFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); return new AlertDialog.Builder(requireContext()) .setMessage(R.string.Parse_error_dlg_text) @@ -63,4 +94,15 @@ public class ParseErrorFragment extends DialogFragment { mInstallActionListener.onNegativeResponse( mDialogData.getActivityResultCode(), mDialogData.getResultIntent()); } + + private void setDialogData(Bundle args) { + int abortReason = args.getInt(ARGS_ABORT_REASON); + String message = args.getString(ARGS_MESSAGE); + Intent resultIntent = args.getParcelable(ARGS_RESULT_INTENT, Intent.class); + int activityResultCode = args.getInt(ARGS_ACTIVITY_RESULT_CODE); + int errorDialogType = args.getInt(ARGS_ERROR_DIALOG_TYPE); + + mDialogData = new InstallAborted(abortReason, message, resultIntent, activityResultCode, + errorDialogType); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/SimpleErrorFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/SimpleErrorFragment.java index 66a353a3519e..8b1ccd8ab6e9 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/SimpleErrorFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/SimpleErrorFragment.java @@ -16,14 +16,18 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_MESSAGE; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallStage; import com.android.packageinstaller.v2.ui.InstallActionListener; @@ -31,11 +35,25 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class SimpleErrorFragment extends DialogFragment { private static final String LOG_TAG = SimpleErrorFragment.class.getSimpleName(); - private final int mMessageResId; + private int mMessageResId; private InstallActionListener mInstallActionListener; - public SimpleErrorFragment(int messageResId) { - mMessageResId = messageResId; + public SimpleErrorFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @return an instance of the fragment + */ + public static SimpleErrorFragment newInstance(int messageResId) { + Bundle args = new Bundle(); + args.putInt(ARGS_MESSAGE, messageResId); + + SimpleErrorFragment fragment = new SimpleErrorFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -47,6 +65,8 @@ public class SimpleErrorFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + mMessageResId = requireArguments().getInt(ARGS_MESSAGE); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + "Dialog message: " + requireContext().getString(mMessageResId)); return new AlertDialog.Builder(requireContext()) diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallConfirmationFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallConfirmationFragment.java index 524b4e6a0e63..860f6a085909 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallConfirmationFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallConfirmationFragment.java @@ -18,6 +18,11 @@ package com.android.packageinstaller.v2.ui.fragments; import static android.text.format.Formatter.formatFileSize; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_DATA_SIZE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_IS_ARCHIVE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_MESSAGE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_TITLE; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; @@ -27,9 +32,11 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.UninstallUserActionRequired; import com.android.packageinstaller.v2.ui.UninstallActionListener; @@ -38,14 +45,34 @@ import com.android.packageinstaller.v2.ui.UninstallActionListener; * Dialog to show while requesting user confirmation for uninstalling an app. */ public class UninstallConfirmationFragment extends DialogFragment { + private static final String LOG_TAG = UninstallConfirmationFragment.class.getSimpleName(); - private final UninstallUserActionRequired mDialogData; + private UninstallUserActionRequired mDialogData; private UninstallActionListener mUninstallActionListener; - private CheckBox mKeepData; - public UninstallConfirmationFragment(UninstallUserActionRequired dialogData) { - mDialogData = dialogData; + public UninstallConfirmationFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link UninstallUserActionRequired} object containing data to + * display in the dialog + * @return an instance of the fragment + */ + public static UninstallConfirmationFragment newInstance( + @NonNull UninstallUserActionRequired dialogData) { + Bundle args = new Bundle(); + args.putLong(ARGS_APP_DATA_SIZE, dialogData.getAppDataSize()); + args.putBoolean(ARGS_IS_ARCHIVE, dialogData.isArchive()); + args.putString(ARGS_TITLE, dialogData.getTitle()); + args.putString(ARGS_MESSAGE, dialogData.getMessage()); + + UninstallConfirmationFragment fragment = new UninstallConfirmationFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -57,6 +84,8 @@ public class UninstallConfirmationFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()) .setTitle(mDialogData.getTitle()) @@ -88,4 +117,13 @@ public class UninstallConfirmationFragment extends DialogFragment { super.onCancel(dialog); mUninstallActionListener.onNegativeResponse(); } + + private void setDialogData(Bundle args) { + long appDataSize = args.getLong(ARGS_APP_DATA_SIZE); + boolean isArchive = args.getBoolean(ARGS_IS_ARCHIVE); + String title = args.getString(ARGS_TITLE); + String message = args.getString(ARGS_MESSAGE); + + mDialogData = new UninstallUserActionRequired(title, message, appDataSize, isArchive); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallErrorFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallErrorFragment.java index 51e16cbff55d..9ed64128088c 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallErrorFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallErrorFragment.java @@ -16,15 +16,19 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ABORT_REASON; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.UninstallAborted; import com.android.packageinstaller.v2.ui.UninstallActionListener; @@ -35,11 +39,27 @@ import com.android.packageinstaller.v2.ui.UninstallActionListener; public class UninstallErrorFragment extends DialogFragment { private static final String LOG_TAG = UninstallErrorFragment.class.getSimpleName(); - private final UninstallAborted mDialogData; + private UninstallAborted mDialogData; private UninstallActionListener mUninstallActionListener; - public UninstallErrorFragment(UninstallAborted dialogData) { - mDialogData = dialogData; + public UninstallErrorFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link UninstallAborted} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static UninstallErrorFragment newInstance(UninstallAborted dialogData) { + Bundle args = new Bundle(); + args.putInt(ARGS_ABORT_REASON, dialogData.getAbortReason()); + + UninstallErrorFragment fragment = new UninstallErrorFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -51,6 +71,8 @@ public class UninstallErrorFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()) .setMessage(mDialogData.getDialogTextResource()) @@ -68,4 +90,9 @@ public class UninstallErrorFragment extends DialogFragment { super.onCancel(dialog); mUninstallActionListener.onNegativeResponse(); } + + private void setDialogData(Bundle args) { + int abortReason = args.getInt(ARGS_ABORT_REASON); + mDialogData = new UninstallAborted(abortReason); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallUninstallingFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallUninstallingFragment.java index 626ff6b92f13..ae56c4d786b8 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallUninstallingFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallUninstallingFragment.java @@ -16,12 +16,17 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_LABEL; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_IS_CLONE_USER; + import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.UninstallUninstalling; @@ -33,13 +38,32 @@ public class UninstallUninstallingFragment extends DialogFragment { private static final String LOG_TAG = UninstallUninstallingFragment.class.getSimpleName(); UninstallUninstalling mDialogData; - public UninstallUninstallingFragment(UninstallUninstalling dialogData) { - mDialogData = dialogData; + UninstallUninstallingFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link UninstallUninstalling} object containing data to display in + * the dialog + * @return an instance of the fragment + */ + public static UninstallUninstallingFragment newInstance(UninstallUninstalling dialogData) { + Bundle args = new Bundle(); + args.putCharSequence(ARGS_APP_LABEL, dialogData.getAppLabel()); + args.putBoolean(ARGS_IS_CLONE_USER, dialogData.isCloneUser()); + + UninstallUninstallingFragment fragment = new UninstallUninstallingFragment(); + fragment.setArguments(args); + return fragment; } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()) .setCancelable(false); @@ -55,4 +79,11 @@ public class UninstallUninstallingFragment extends DialogFragment { return dialog; } + + private void setDialogData(Bundle args) { + CharSequence label = args.getCharSequence(ARGS_APP_LABEL); + boolean isCloneUser = args.getBoolean(ARGS_IS_CLONE_USER); + + mDialogData = new UninstallUninstalling(label, isCloneUser); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt index 388e03f023a1..5a2b122f0bec 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/viewmodel/InstallViewModel.kt @@ -49,6 +49,20 @@ class InstallViewModel(application: Application, val repository: InstallReposito _currentInstallStage.value = installStage } } + + // Since staging is an async operation, we will get the staging result later in time. + // Result of the file staging will be set in InstallRepository#mStagingResult. + // As such, mCurrentInstallStage will need to add another MutableLiveData + // as a data source + _currentInstallStage.addSource( + repository.stagingResult.distinctUntilChanged() + ) { installStage: InstallStage -> + if (installStage.stageCode != InstallStage.STAGE_READY) { + _currentInstallStage.value = installStage + } else { + checkIfAllowedAndInitiateInstall() + } + } } fun preprocessIntent(intent: Intent, callerInfo: InstallRepository.CallerInfo) { @@ -56,18 +70,7 @@ class InstallViewModel(application: Application, val repository: InstallReposito if (stage.stageCode == InstallStage.STAGE_ABORTED) { _currentInstallStage.value = stage } else { - // Since staging is an async operation, we will get the staging result later in time. - // Result of the file staging will be set in InstallRepository#mStagingResult. - // As such, mCurrentInstallStage will need to add another MutableLiveData - // as a data source repository.stageForInstall() - _currentInstallStage.addSource(repository.stagingResult) { installStage: InstallStage -> - if (installStage.stageCode != InstallStage.STAGE_READY) { - _currentInstallStage.value = installStage - } else { - checkIfAllowedAndInitiateInstall() - } - } } } diff --git a/packages/SettingsLib/AndroidManifest.xml b/packages/SettingsLib/AndroidManifest.xml index 412ff29aec32..473b7eb07666 100644 --- a/packages/SettingsLib/AndroidManifest.xml +++ b/packages/SettingsLib/AndroidManifest.xml @@ -21,6 +21,13 @@ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <application> + <activity + android:name=".users.CreateUserActivity" + android:excludeFromRecents="true" + android:exported="false" + android:finishOnCloseSystemDialogs="true" + android:launchMode="singleInstance" + android:theme="@style/Theme.Transparent"/> </application> </manifest> diff --git a/packages/SettingsLib/BannerMessagePreference/Android.bp b/packages/SettingsLib/BannerMessagePreference/Android.bp index 182daeb45d7c..203a3bf64910 100644 --- a/packages/SettingsLib/BannerMessagePreference/Android.bp +++ b/packages/SettingsLib/BannerMessagePreference/Android.bp @@ -31,5 +31,6 @@ android_library { apex_available: [ "//apex_available:platform", "com.android.healthfitness", + "com.android.permission", ], } diff --git a/packages/SettingsLib/BannerMessagePreference/res/drawable-v35/settingslib_resolved_banner_avd.xml b/packages/SettingsLib/BannerMessagePreference/res/drawable-v35/settingslib_resolved_banner_avd.xml new file mode 100644 index 000000000000..c999de7d99ea --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/res/drawable-v35/settingslib_resolved_banner_avd.xml @@ -0,0 +1,157 @@ +<!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt"> + <aapt:attr name="android:drawable"> + <vector + android:width="112dp" + android:height="112dp" + android:viewportHeight="112" + android:viewportWidth="112"> + <group android:name="_R_G"> + <group + android:name="_R_G_L_1_G" + android:translateX="56.5" + android:translateY="56.625"> + <path + android:name="_R_G_L_1_G_D_0_P_0" + android:fillAlpha="0" + android:fillColor="?android:attr/textColorPrimary" + android:fillType="nonZero" + android:pathData=" M-14.75 -0.59 C-14.75,-0.59 -15.32,-1.16 -15.32,-1.16 C-15.32,-1.16 -14.67,-0.73 -14.67,-0.73 C-14.67,-0.73 -14.39,-0.44 -14.39,-0.44 C-14.39,-0.44 -17.32,2.5 -17.32,2.5 C-17.32,2.5 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c " + android:trimPathEnd="1" + android:trimPathOffset="0" + android:trimPathStart="0" /> + </group> + <group + android:name="_R_G_L_0_G" + android:rotation="-90" + android:translateX="56" + android:translateY="56"> + <path + android:name="_R_G_L_0_G_D_0_P_0" + android:pathData=" M53.5 0 C53.5,-29.53 29.53,-53.5 0,-53.5 C0,-53.5 0,-53.5 0,-53.5 C-29.53,-53.5 -53.5,-29.53 -53.5,0 C-53.5,0 -53.5,0 -53.5,0 C-53.5,29.53 -29.53,53.5 0,53.5 C0,53.5 0,53.5 0,53.5 C29.53,53.5 53.5,29.53 53.5,0 C53.5,0 53.5,0 53.5,0c " + android:strokeAlpha="1" + android:strokeColor="?android:attr/textColorTertiary" + android:strokeLineCap="round" + android:strokeLineJoin="round" + android:strokeWidth="5" + android:trimPathEnd="0" + android:trimPathOffset="0" + android:trimPathStart="0" /> + </group> + </group> + <group android:name="time_group" /> + </vector> + </aapt:attr> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="400" + android:propertyName="fillAlpha" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="0" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:startOffset="400" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_1_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="400" + android:propertyName="pathData" + android:startOffset="0" + android:valueFrom="M-14.75 -0.59 C-14.75,-0.59 -15.32,-1.16 -15.32,-1.16 C-15.32,-1.16 -14.67,-0.73 -14.67,-0.73 C-14.67,-0.73 -14.39,-0.44 -14.39,-0.44 C-14.39,-0.44 -17.32,2.5 -17.32,2.5 C-17.32,2.5 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c " + android:valueTo="M-14.75 -0.59 C-14.75,-0.59 -15.32,-1.16 -15.32,-1.16 C-15.32,-1.16 -14.67,-0.73 -14.67,-0.73 C-14.67,-0.73 -14.39,-0.44 -14.39,-0.44 C-14.39,-0.44 -17.32,2.5 -17.32,2.5 C-17.32,2.5 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="83" + android:propertyName="pathData" + android:startOffset="400" + android:valueFrom="M-14.75 -0.59 C-14.75,-0.59 -15.32,-1.16 -15.32,-1.16 C-15.32,-1.16 -14.67,-0.73 -14.67,-0.73 C-14.67,-0.73 -14.39,-0.44 -14.39,-0.44 C-14.39,-0.44 -17.32,2.5 -17.32,2.5 C-17.32,2.5 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c " + android:valueTo="M-14.75 -0.59 C-14.75,-0.59 -6.41,7.75 -6.41,7.75 C-6.41,7.75 -6.3,7.65 -6.3,7.65 C-6.3,7.65 -3.48,10.47 -3.48,10.47 C-3.48,10.47 -6.41,13.41 -6.41,13.41 C-6.41,13.41 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + <objectAnimator + android:duration="167" + android:propertyName="pathData" + android:startOffset="483" + android:valueFrom="M-14.75 -0.59 C-14.75,-0.59 -6.41,7.75 -6.41,7.75 C-6.41,7.75 -6.3,7.65 -6.3,7.65 C-6.3,7.65 -3.48,10.47 -3.48,10.47 C-3.48,10.47 -6.41,13.41 -6.41,13.41 C-6.41,13.41 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c " + android:valueTo="M-14.75 -0.59 C-14.75,-0.59 -6.41,7.75 -6.41,7.75 C-6.41,7.75 14.77,-13.41 14.77,-13.41 C14.77,-13.41 17.59,-10.59 17.59,-10.59 C17.59,-10.59 -6.41,13.41 -6.41,13.41 C-6.41,13.41 -17.59,2.23 -17.59,2.23 C-17.59,2.23 -14.75,-0.59 -14.75,-0.59c " + android:valueType="pathType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.667,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="_R_G_L_0_G_D_0_P_0"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="500" + android:propertyName="trimPathEnd" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType"> + <aapt:attr name="android:interpolator"> + <pathInterpolator android:pathData="M 0.0,0.0 c0.2,0 0,1 1.0,1.0" /> + </aapt:attr> + </objectAnimator> + </set> + </aapt:attr> + </target> + <target android:name="time_group"> + <aapt:attr name="android:animation"> + <set android:ordering="together"> + <objectAnimator + android:duration="667" + android:propertyName="translateX" + android:startOffset="0" + android:valueFrom="0" + android:valueTo="1" + android:valueType="floatType" /> + </set> + </aapt:attr> + </target> +</animated-vector>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/layout-v35/settingslib_expressive_banner_message.xml b/packages/SettingsLib/BannerMessagePreference/res/layout-v35/settingslib_expressive_banner_message.xml index b10ef6e77ec7..c448a2d434f8 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/layout-v35/settingslib_expressive_banner_message.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/layout-v35/settingslib_expressive_banner_message.xml @@ -28,81 +28,104 @@ android:orientation="vertical" style="@style/Banner.Preference.SettingsLib.Expressive"> - <RelativeLayout - android:id="@+id/top_row" + <FrameLayout android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> + android:layout_height="wrap_content"> <LinearLayout + android:id="@+id/banner_content" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentStart="true" - android:layout_marginEnd="@dimen/settingslib_expressive_space_medium4" android:orientation="vertical"> - <TextView - android:id="@+id/banner_header" + + <RelativeLayout + android:id="@+id/top_row" android:layout_width="match_parent" android:layout_height="wrap_content" - style="@style/Banner.Header.SettingsLib.Expressive"/> + android:orientation="horizontal"> - <LinearLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content"> - - <ImageView - android:id="@+id/banner_icon" - android:layout_width="@dimen/settingslib_expressive_space_small3" - android:layout_height="@dimen/settingslib_expressive_space_small3" - android:layout_gravity="center_vertical" - android:importantForAccessibility="no" - android:scaleType="fitCenter" /> - - <TextView - android:id="@+id/banner_title" + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - style="@style/Banner.Title.SettingsLib.Expressive" /> - </LinearLayout> + android:layout_alignParentStart="true" + android:layout_marginEnd="@dimen/settingslib_expressive_space_medium4" + android:orientation="vertical"> + <TextView + android:id="@+id/banner_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Banner.Header.SettingsLib.Expressive"/> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/banner_icon" + android:layout_width="@dimen/settingslib_expressive_space_small3" + android:layout_height="@dimen/settingslib_expressive_space_small3" + android:layout_gravity="center_vertical" + android:layout_marginEnd="@dimen/settingslib_expressive_space_extrasmall4" + android:importantForAccessibility="no" + android:scaleType="fitCenter" /> + + <TextView + android:id="@+id/banner_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Banner.Title.SettingsLib.Expressive" /> + </LinearLayout> + + <TextView + android:id="@+id/banner_subtitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Banner.Subtitle.SettingsLib.Expressive"/> + </LinearLayout> + + <ImageButton + android:id="@+id/banner_dismiss_btn" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/accessibility_banner_message_dismiss" + style="@style/Banner.Dismiss.SettingsLib.Expressive" /> + </RelativeLayout> <TextView - android:id="@+id/banner_subtitle" + android:id="@+id/banner_summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/Banner.Summary.SettingsLib.Expressive"/> + + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - style="@style/Banner.Subtitle.SettingsLib.Expressive"/> + android:id="@+id/banner_buttons_frame" + android:paddingTop="@dimen/settingslib_expressive_space_extrasmall6" + android:orientation="horizontal"> + + <com.google.android.material.button.MaterialButton + android:id="@+id/banner_negative_btn" + android:layout_weight="1" + style="@style/Banner.NegativeButton.SettingsLib.Expressive"/> + <Space + android:id="@+id/banner_button_space" + android:layout_width="@dimen/settingslib_expressive_space_extrasmall4" + android:layout_height="@dimen/settingslib_expressive_space_small1"/> + <com.google.android.material.button.MaterialButton + android:id="@+id/banner_positive_btn" + android:layout_weight="1" + style="@style/Banner.PositiveButton.SettingsLib.Expressive"/> + </LinearLayout> </LinearLayout> - <ImageButton - android:id="@+id/banner_dismiss_btn" + <TextView + android:id="@+id/resolved_banner_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@style/Banner.Dismiss.SettingsLib.Expressive" /> - </RelativeLayout> - - <TextView - android:id="@+id/banner_summary" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - style="@style/Banner.Summary.SettingsLib.Expressive"/> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:id="@+id/banner_buttons_frame" - android:paddingTop="@dimen/settingslib_expressive_space_extrasmall6" - android:orientation="horizontal"> - - <com.google.android.material.button.MaterialButton - android:id="@+id/banner_negative_btn" - android:layout_weight="1" - style="@style/Banner.NegativeButton.SettingsLib.Expressive"/> - <Space - android:layout_width="@dimen/settingslib_expressive_space_extrasmall4" - android:layout_height="@dimen/settingslib_expressive_space_small1"/> - <com.google.android.material.button.MaterialButton - android:id="@+id/banner_positive_btn" - android:layout_weight="1" - style="@style/Banner.PositiveButton.SettingsLib.Expressive"/> - </LinearLayout> + android:drawableTop="@drawable/settingslib_resolved_banner_avd" + android:visibility="gone" + style="@style/Banner.ResolvedText.SettingsLib.Expressive"/> + </FrameLayout> </com.android.settingslib.widget.BannerMessageView> </LinearLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v35/styles_expressive.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v35/styles_expressive.xml index b864311bf9b7..09e07ccef683 100644 --- a/packages/SettingsLib/BannerMessagePreference/res/values-v35/styles_expressive.xml +++ b/packages/SettingsLib/BannerMessagePreference/res/values-v35/styles_expressive.xml @@ -33,7 +33,6 @@ <style name="Banner.Title.SettingsLib.Expressive" parent=""> <item name="android:layout_gravity">start</item> - <item name="android:layout_marginLeft">@dimen/settingslib_expressive_space_extrasmall4</item> <item name="android:textAlignment">viewStart</item> <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleLarge.Emphasized</item> <item name="android:textColor">?android:attr/textColorPrimary</item> @@ -73,4 +72,11 @@ parent="@style/SettingsLibButtonStyle.Expressive.Outline.Extra"> <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Small</item> </style> + + <style name="Banner.ResolvedText.SettingsLib.Expressive" parent=""> + <item name="android:layout_gravity">center</item> + <item name="android:drawablePadding">@dimen/settingslib_expressive_space_small1</item> + <item name="android:textAppearance">@style/TextAppearance.SettingsLib.BodyMedium</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + </style> </resources> diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java index c82829d6ccea..c90a76a39510 100644 --- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java +++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessagePreference.java @@ -35,6 +35,8 @@ import android.widget.TextView; import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.StringRes; import androidx.preference.Preference; @@ -43,6 +45,9 @@ import androidx.preference.PreferenceViewHolder; import com.android.settingslib.widget.preference.banner.R; import com.google.android.material.button.MaterialButton; + +import java.util.Objects; + /** * Banner message is a banner displaying important information (permission request, page error etc), * and provide actions for user to address. It requires a user action to be dismissed. @@ -67,13 +72,15 @@ public class BannerMessagePreference extends Preference implements GroupSectionD R.color.banner_accent_attention_normal, R.color.settingslib_banner_button_background_normal); - // Corresponds to the enum valye of R.attr.attentionLevel + // Corresponds to the enum value of R.attr.attentionLevel private final int mAttrValue; @ColorRes private final int mBackgroundColorResId; @ColorRes private final int mAccentColorResId; @ColorRes private final int mButtonBackgroundColorResId; - AttentionLevel(int attrValue, @ColorRes int backgroundColorResId, + AttentionLevel( + int attrValue, + @ColorRes int backgroundColorResId, @ColorRes int accentColorResId, @ColorRes int buttonBackgroundColorResId) { mAttrValue = attrValue; @@ -115,33 +122,38 @@ public class BannerMessagePreference extends Preference implements GroupSectionD new BannerMessagePreference.DismissButtonInfo(); // Default attention level is High. - private AttentionLevel mAttentionLevel = AttentionLevel.HIGH; - private CharSequence mSubtitle; - private CharSequence mHeader; + @NonNull private AttentionLevel mAttentionLevel = AttentionLevel.HIGH; + @Nullable private CharSequence mSubtitle; + @Nullable private CharSequence mHeader; private int mButtonOrientation; + @Nullable private ResolutionAnimator.Data mResolutionData; - public BannerMessagePreference(Context context) { + public BannerMessagePreference(@NonNull Context context) { super(context); init(context, null /* attrs */); } - public BannerMessagePreference(Context context, AttributeSet attrs) { + public BannerMessagePreference(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context, attrs); } - public BannerMessagePreference(Context context, AttributeSet attrs, int defStyleAttr) { + public BannerMessagePreference( + @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } - public BannerMessagePreference(Context context, AttributeSet attrs, int defStyleAttr, + public BannerMessagePreference( + @NonNull Context context, + @Nullable AttributeSet attrs, + int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(context, attrs); } - private void init(Context context, AttributeSet attrs) { + private void init(@NonNull Context context, @Nullable AttributeSet attrs) { setSelectable(false); int resId = SettingsThemeHelper.isExpressiveTheme(context) ? R.layout.settingslib_expressive_banner_message @@ -166,7 +178,7 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } @Override - public void onBindViewHolder(PreferenceViewHolder holder) { + public void onBindViewHolder(@NonNull PreferenceViewHolder holder) { super.onBindViewHolder(holder); final Context context = getContext(); @@ -193,14 +205,20 @@ public class BannerMessagePreference extends Preference implements GroupSectionD final ImageView iconView = (ImageView) holder.findViewById(R.id.banner_icon); if (iconView != null) { Drawable icon = getIcon(); - iconView.setImageDrawable( - icon == null - ? getContext().getDrawable(R.drawable.ic_warning) - : icon); - if (mAttentionLevel != AttentionLevel.NORMAL - && !SettingsThemeHelper.isExpressiveTheme(context)) { - iconView.setColorFilter( - new PorterDuffColorFilter(accentColor, PorterDuff.Mode.SRC_IN)); + + if (icon == null && SettingsThemeHelper.isExpressiveTheme(context)) { + iconView.setVisibility(View.GONE); + } else { + iconView.setVisibility(View.VISIBLE); + iconView.setImageDrawable( + icon == null + ? getContext().getDrawable(R.drawable.ic_warning) + : icon); + if (mAttentionLevel != AttentionLevel.NORMAL + && !SettingsThemeHelper.isExpressiveTheme(context)) { + iconView.setColorFilter( + new PorterDuffColorFilter(accentColor, PorterDuff.Mode.SRC_IN)); + } } } @@ -233,8 +251,10 @@ public class BannerMessagePreference extends Preference implements GroupSectionD mDismissButtonInfo.setUpButton(); final TextView subtitleView = (TextView) holder.findViewById(R.id.banner_subtitle); - subtitleView.setText(mSubtitle); - subtitleView.setVisibility(mSubtitle == null ? View.GONE : View.VISIBLE); + if (subtitleView != null) { + subtitleView.setText(mSubtitle); + subtitleView.setVisibility(mSubtitle == null ? View.GONE : View.VISIBLE); + } TextView headerView = (TextView) holder.findViewById(R.id.banner_header); if (headerView != null) { @@ -268,11 +288,25 @@ public class BannerMessagePreference extends Preference implements GroupSectionD linearLayout.setOrientation(mButtonOrientation); } } + + View buttonSpace = holder.findViewById(R.id.banner_button_space); + if (buttonSpace != null) { + if (mPositiveButtonInfo.shouldBeVisible() && mNegativeButtonInfo.shouldBeVisible()) { + buttonSpace.setVisibility(View.VISIBLE); + } else { + buttonSpace.setVisibility(View.GONE); + } + } + + if (mResolutionData != null) { + new ResolutionAnimator(mResolutionData, holder).startResolutionAnimation(); + } } /** - * Set the visibility state of positive button. + * Sets the visibility state of the positive button. */ + @NonNull public BannerMessagePreference setPositiveButtonVisible(boolean isVisible) { if (isVisible != mPositiveButtonInfo.mIsVisible) { mPositiveButtonInfo.mIsVisible = isVisible; @@ -282,8 +316,9 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } /** - * Set the visibility state of negative button. + * Sets the visibility state of the negative button. */ + @NonNull public BannerMessagePreference setNegativeButtonVisible(boolean isVisible) { if (isVisible != mNegativeButtonInfo.mIsVisible) { mNegativeButtonInfo.mIsVisible = isVisible; @@ -293,9 +328,10 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } /** - * Set the visibility state of dismiss button. + * Sets the visibility state of the dismiss button. */ @RequiresApi(Build.VERSION_CODES.S) + @NonNull public BannerMessagePreference setDismissButtonVisible(boolean isVisible) { if (isVisible != mDismissButtonInfo.mIsVisible) { mDismissButtonInfo.mIsVisible = isVisible; @@ -305,10 +341,35 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } /** - * Register a callback to be invoked when positive button is clicked. + * Sets the enabled state of the positive button. + */ + @NonNull + public BannerMessagePreference setPositiveButtonEnabled(boolean isEnabled) { + if (isEnabled != mPositiveButtonInfo.mIsEnabled) { + mPositiveButtonInfo.mIsEnabled = isEnabled; + notifyChanged(); + } + return this; + } + + /** + * Sets the enabled state of the negative button. + */ + @NonNull + public BannerMessagePreference setNegativeButtonEnabled(boolean isEnabled) { + if (isEnabled != mNegativeButtonInfo.mIsEnabled) { + mNegativeButtonInfo.mIsEnabled = isEnabled; + notifyChanged(); + } + return this; + } + + /** + * Registers a callback to be invoked when positive button is clicked. */ + @NonNull public BannerMessagePreference setPositiveButtonOnClickListener( - View.OnClickListener listener) { + @Nullable View.OnClickListener listener) { if (listener != mPositiveButtonInfo.mListener) { mPositiveButtonInfo.mListener = listener; notifyChanged(); @@ -317,10 +378,11 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } /** - * Register a callback to be invoked when negative button is clicked. + * Registers a callback to be invoked when negative button is clicked. */ + @NonNull public BannerMessagePreference setNegativeButtonOnClickListener( - View.OnClickListener listener) { + @Nullable View.OnClickListener listener) { if (listener != mNegativeButtonInfo.mListener) { mNegativeButtonInfo.mListener = listener; notifyChanged(); @@ -329,11 +391,12 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } /** - * Register a callback to be invoked when the dismiss button is clicked. + * Registers a callback to be invoked when the dismiss button is clicked. */ @RequiresApi(Build.VERSION_CODES.S) + @NonNull public BannerMessagePreference setDismissButtonOnClickListener( - View.OnClickListener listener) { + @Nullable View.OnClickListener listener) { if (listener != mDismissButtonInfo.mListener) { mDismissButtonInfo.mListener = listener; notifyChanged(); @@ -344,6 +407,7 @@ public class BannerMessagePreference extends Preference implements GroupSectionD /** * Sets the text to be displayed in positive button. */ + @NonNull public BannerMessagePreference setPositiveButtonText(@StringRes int textResId) { return setPositiveButtonText(getContext().getString(textResId)); } @@ -351,7 +415,9 @@ public class BannerMessagePreference extends Preference implements GroupSectionD /** * Sets the text to be displayed in positive button. */ - public BannerMessagePreference setPositiveButtonText(CharSequence positiveButtonText) { + @NonNull + public BannerMessagePreference setPositiveButtonText( + @Nullable CharSequence positiveButtonText) { if (!TextUtils.equals(positiveButtonText, mPositiveButtonInfo.mText)) { mPositiveButtonInfo.mText = positiveButtonText; notifyChanged(); @@ -362,6 +428,7 @@ public class BannerMessagePreference extends Preference implements GroupSectionD /** * Sets the text to be displayed in negative button. */ + @NonNull public BannerMessagePreference setNegativeButtonText(@StringRes int textResId) { return setNegativeButtonText(getContext().getString(textResId)); } @@ -369,7 +436,9 @@ public class BannerMessagePreference extends Preference implements GroupSectionD /** * Sets the text to be displayed in negative button. */ - public BannerMessagePreference setNegativeButtonText(CharSequence negativeButtonText) { + @NonNull + public BannerMessagePreference setNegativeButtonText( + @Nullable CharSequence negativeButtonText) { if (!TextUtils.equals(negativeButtonText, mNegativeButtonInfo.mText)) { mNegativeButtonInfo.mText = negativeButtonText; notifyChanged(); @@ -380,8 +449,12 @@ public class BannerMessagePreference extends Preference implements GroupSectionD /** * Sets button orientation. */ - @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @NonNull public BannerMessagePreference setButtonOrientation(int orientation) { + if (!SettingsThemeHelper.isExpressiveTheme(getContext())) { + return this; + } + if (mButtonOrientation != orientation) { mButtonOrientation = orientation; notifyChanged(); @@ -393,6 +466,7 @@ public class BannerMessagePreference extends Preference implements GroupSectionD * Sets the subtitle. */ @RequiresApi(Build.VERSION_CODES.S) + @NonNull public BannerMessagePreference setSubtitle(@StringRes int textResId) { return setSubtitle(getContext().getString(textResId)); } @@ -401,7 +475,8 @@ public class BannerMessagePreference extends Preference implements GroupSectionD * Sets the subtitle. */ @RequiresApi(Build.VERSION_CODES.S) - public BannerMessagePreference setSubtitle(CharSequence subtitle) { + @NonNull + public BannerMessagePreference setSubtitle(@Nullable CharSequence subtitle) { if (!TextUtils.equals(subtitle, mSubtitle)) { mSubtitle = subtitle; notifyChanged(); @@ -412,7 +487,7 @@ public class BannerMessagePreference extends Preference implements GroupSectionD /** * Sets the header. */ - @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) + @NonNull public BannerMessagePreference setHeader(@StringRes int textResId) { return setHeader(getContext().getString(textResId)); } @@ -420,8 +495,12 @@ public class BannerMessagePreference extends Preference implements GroupSectionD /** * Sets the header. */ - @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) - public BannerMessagePreference setHeader(CharSequence header) { + @NonNull + public BannerMessagePreference setHeader(@Nullable CharSequence header) { + if (!SettingsThemeHelper.isExpressiveTheme(getContext())) { + return this; + } + if (!TextUtils.equals(header, mHeader)) { mHeader = header; notifyChanged(); @@ -430,32 +509,75 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } /** - * Sets the attention level. This will update the color theme of the preference. + * Plays a resolution animation, showing the given message. */ - public BannerMessagePreference setAttentionLevel(AttentionLevel attentionLevel) { - if (attentionLevel == mAttentionLevel) { + @NonNull + public BannerMessagePreference showResolutionAnimation( + @NonNull CharSequence resolutionMessage, + @NonNull ResolutionCompletedCallback onCompletionCallback) { + if (!SettingsThemeHelper.isExpressiveTheme(getContext())) { return this; } + ResolutionAnimator.Data resolutionData = + new ResolutionAnimator.Data(resolutionMessage, onCompletionCallback); + if (!Objects.equals(mResolutionData, resolutionData)) { + mResolutionData = resolutionData; + notifyChanged(); + } + return this; + } - if (attentionLevel != null) { - mAttentionLevel = attentionLevel; + /** + * Removes the resolution animation from this preference. + * + * <p>Should be called after the resolution animation completes if this preference will be + * reused. Otherwise the resolution animation will be played everytime this preference is + * displayed. + */ + @NonNull + public BannerMessagePreference clearResolutionAnimation() { + if (!SettingsThemeHelper.isExpressiveTheme(getContext())) { + return this; + } + if (mResolutionData != null) { + mResolutionData = null; notifyChanged(); } return this; } + /** + * Sets the attention level. This will update the color theme of the preference. + */ + @NonNull + public BannerMessagePreference setAttentionLevel(@NonNull AttentionLevel attentionLevel) { + if (attentionLevel == mAttentionLevel) { + return this; + } + + mAttentionLevel = attentionLevel; + notifyChanged(); + return this; + } + static class ButtonInfo { - private Button mButton; - private CharSequence mText; - private View.OnClickListener mListener; + @Nullable private Button mButton; + @Nullable private CharSequence mText; + @Nullable private View.OnClickListener mListener; private boolean mIsVisible = true; + private boolean mIsEnabled = true; @ColorInt private int mColor; @ColorInt private int mBackgroundColor; - private ColorStateList mStrokeColor; + @Nullable private ColorStateList mStrokeColor; void setUpButton() { + if (mButton == null) { + return; + } + mButton.setText(mText); mButton.setOnClickListener(mListener); + mButton.setEnabled(mIsEnabled); MaterialButton btn = null; if (mButton instanceof MaterialButton) { @@ -492,11 +614,15 @@ public class BannerMessagePreference extends Preference implements GroupSectionD } static class DismissButtonInfo { - private ImageButton mButton; - private View.OnClickListener mListener; + @Nullable private ImageButton mButton; + @Nullable private View.OnClickListener mListener; private boolean mIsVisible = true; void setUpButton() { + if (mButton == null) { + return; + } + mButton.setOnClickListener(mListener); if (shouldBeVisible()) { mButton.setVisibility(View.VISIBLE); diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessageView.java b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessageView.java index ff4e79ddaaa1..eabb6341c3dd 100644 --- a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessageView.java +++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/BannerMessageView.java @@ -23,6 +23,7 @@ import android.view.TouchDelegate; import android.view.View; import android.widget.LinearLayout; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.settingslib.widget.preference.banner.R; @@ -34,22 +35,25 @@ import com.android.settingslib.widget.preference.banner.R; * {@link BannerMessagePreference} to a {@code PreferenceScreen}. */ public class BannerMessageView extends LinearLayout { - private Rect mTouchTargetForDismissButton; + @Nullable private Rect mTouchTargetForDismissButton; - public BannerMessageView(Context context) { + public BannerMessageView(@NonNull Context context) { super(context); } - public BannerMessageView(Context context, - @Nullable AttributeSet attrs) { + public BannerMessageView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } - public BannerMessageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + public BannerMessageView( + @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } - public BannerMessageView(Context context, AttributeSet attrs, int defStyleAttr, + public BannerMessageView( + @NonNull Context context, + @Nullable AttributeSet attrs, + int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } diff --git a/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/ResolutionAnimator.kt b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/ResolutionAnimator.kt new file mode 100644 index 000000000000..fbf910a42423 --- /dev/null +++ b/packages/SettingsLib/BannerMessagePreference/src/com/android/settingslib/widget/ResolutionAnimator.kt @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.widget + +import android.graphics.drawable.Animatable2 +import android.graphics.drawable.AnimatedVectorDrawable +import android.graphics.drawable.Drawable +import android.os.Build +import android.provider.DeviceConfig +import android.transition.Fade +import android.transition.Transition +import android.transition.TransitionListenerAdapter +import android.transition.TransitionManager +import android.transition.TransitionSet +import android.view.View +import android.view.ViewGroup +import android.view.animation.LinearInterpolator +import android.widget.TextView +import androidx.preference.PreferenceViewHolder +import com.android.settingslib.widget.preference.banner.R +import java.time.Duration + +/** Callback to communicate when a banner message resolution animation is completed. */ +fun interface ResolutionCompletedCallback { + fun onCompleted() +} + +internal class ResolutionAnimator( + private val data: Data, + private val preferenceViewHolder: PreferenceViewHolder, +) { + + data class Data( + val resolutionMessage: CharSequence, + val resolutionCompletedCallback: ResolutionCompletedCallback, + ) + + private val defaultBannerContent: View? + get() = preferenceViewHolder.findView(R.id.banner_content) + private val resolvedTextView: TextView? + get() = preferenceViewHolder.findView(R.id.resolved_banner_text) + + fun startResolutionAnimation() { + resolvedTextView?.text = data.resolutionMessage + resolvedTextView?.resolutionDrawable?.reset() + + val transitionSet = + TransitionSet() + .setOrdering(TransitionSet.ORDERING_SEQUENTIAL) + .setInterpolator(linearInterpolator) + .addTransition(hideIssueContentTransition) + .addTransition( + showResolvedContentTransition + .clone() + .addListener( + object : TransitionListenerAdapter() { + override fun onTransitionEnd(transition: Transition) { + super.onTransitionEnd(transition) + startIssueResolvedAnimation() + } + } + ) + ) + + preferenceViewHolder.itemView.post { + TransitionManager.beginDelayedTransition( + preferenceViewHolder.itemView as ViewGroup, + transitionSet, + ) + + defaultBannerContent?.visibility = View.INVISIBLE + resolvedTextView?.visibility = View.VISIBLE + } + + preferenceViewHolder.itemView.addOnAttachStateChangeListener( + object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(v: View) {} + + override fun onViewDetachedFromWindow(v: View) { + v.removeOnAttachStateChangeListener(this) + cancelAnimationsAndFinish() + } + } + ) + } + + private fun startIssueResolvedAnimation() { + val animatedDrawable = resolvedTextView?.resolutionDrawable + + if (animatedDrawable == null) { + hideResolvedUiAndFinish() + return + } + + animatedDrawable.apply { + clearAnimationCallbacks() + registerAnimationCallback( + object : Animatable2.AnimationCallback() { + override fun onAnimationEnd(drawable: Drawable) { + super.onAnimationEnd(drawable) + hideResolvedUiAndFinish() + } + } + ) + start() + } + } + + private fun hideResolvedUiAndFinish() { + val hideTransition = + hideResolvedContentTransition + .clone() + .setInterpolator(linearInterpolator) + .addListener( + object : TransitionListenerAdapter() { + override fun onTransitionEnd(transition: Transition) { + super.onTransitionEnd(transition) + data.resolutionCompletedCallback.onCompleted() + } + } + ) + TransitionManager.beginDelayedTransition( + preferenceViewHolder.itemView as ViewGroup, + hideTransition, + ) + resolvedTextView?.visibility = View.GONE + } + + private fun cancelAnimationsAndFinish() { + TransitionManager.endTransitions(preferenceViewHolder.itemView as ViewGroup) + + resolvedTextView?.visibility = View.GONE + + val animatedDrawable = resolvedTextView?.resolutionDrawable + animatedDrawable?.clearAnimationCallbacks() + animatedDrawable?.stop() + + data.resolutionCompletedCallback.onCompleted() + } + + private companion object { + private val linearInterpolator = LinearInterpolator() + + private val HIDE_ISSUE_CONTENT_TRANSITION_DURATION = Duration.ofMillis(333) + private val hideIssueContentTransition = + Fade(Fade.OUT).setDuration(HIDE_ISSUE_CONTENT_TRANSITION_DURATION.toMillis()) + + private val SHOW_RESOLVED_CONTENT_TRANSITION_DELAY = Duration.ofMillis(133) + private val SHOW_RESOLVED_CONTENT_TRANSITION_DURATION = Duration.ofMillis(250) + private val showResolvedContentTransition = + Fade(Fade.IN) + .setStartDelay(SHOW_RESOLVED_CONTENT_TRANSITION_DELAY.toMillis()) + .setDuration(SHOW_RESOLVED_CONTENT_TRANSITION_DURATION.toMillis()) + + private val hideResolvedContentTransitionDelay + get() = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Duration.ofMillis( + DeviceConfig.getLong( + "settings_ui", + "banner_message_pref_hide_resolved_content_delay_millis", + 400, + ) + ) + } else { + Duration.ofMillis(400) + } + + private val HIDE_RESOLVED_UI_TRANSITION_DURATION = Duration.ofMillis(167) + private val hideResolvedContentTransition + get() = + Fade(Fade.OUT) + .setStartDelay(hideResolvedContentTransitionDelay.toMillis()) + .setDuration(HIDE_RESOLVED_UI_TRANSITION_DURATION.toMillis()) + + inline fun <reified T : View> PreferenceViewHolder.findView(id: Int): T? = + findViewById(id) as? T + + val TextView.resolutionDrawable: AnimatedVectorDrawable? + get() = compoundDrawables.find { it != null } as? AnimatedVectorDrawable + } +} diff --git a/packages/SettingsLib/ButtonPreference/Android.bp b/packages/SettingsLib/ButtonPreference/Android.bp index a377f312ffbf..c8375a992d30 100644 --- a/packages/SettingsLib/ButtonPreference/Android.bp +++ b/packages/SettingsLib/ButtonPreference/Android.bp @@ -30,5 +30,6 @@ android_library { apex_available: [ "//apex_available:platform", "com.android.healthfitness", + "com.android.permission", ], } diff --git a/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml b/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml index a0d10c383445..56b05159a30f 100644 --- a/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml +++ b/packages/SettingsLib/IllustrationPreference/AndroidManifest.xml @@ -18,6 +18,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.settingslib.widget.preference.illustration"> - <uses-sdk android:minSdkVersion="28" /> + <uses-sdk android:minSdkVersion="30" /> </manifest> diff --git a/packages/SettingsLib/IllustrationPreference/res/values/strings.xml b/packages/SettingsLib/IllustrationPreference/res/values/strings.xml new file mode 100644 index 000000000000..3a8aaf8b5092 --- /dev/null +++ b/packages/SettingsLib/IllustrationPreference/res/values/strings.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Label for an accessibility action that starts an animation [CHAR LIMIT=30] --> + <string name="settingslib_action_label_resume">resume</string> + <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=30] --> + <string name="settingslib_action_label_pause">pause</string> + <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=50] --> + <string name="settingslib_state_animation_playing">Animation playing</string> + <!-- Label for an accessibility action that stops an animation [CHAR LIMIT=50] --> + <string name="settingslib_state_animation_paused">Animation paused</string> +</resources> diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java index af40c647e805..e818a603c5b4 100644 --- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java +++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java @@ -32,6 +32,8 @@ import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.widget.FrameLayout; import android.widget.ImageView; @@ -73,6 +75,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi private boolean mLottieDynamicColor; private CharSequence mContentDescription; private boolean mIsTablet; + private boolean mIsAnimatable; private boolean mIsAnimationPaused; /** @@ -81,6 +84,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi public interface OnBindListener { /** * Called when when {@link #onBindViewHolder(PreferenceViewHolder)} occurs. + * * @param animationView the animation view for this preference. */ void onBind(LottieAnimationView animationView); @@ -144,16 +148,6 @@ public class IllustrationPreference extends Preference implements GroupSectionDi (FrameLayout) holder.findViewById(R.id.middleground_layout); final LottieAnimationView illustrationView = (LottieAnimationView) holder.findViewById(R.id.lottie_view); - // Pause and resume animation - illustrationFrame.setOnClickListener(v -> { - mIsAnimationPaused = !mIsAnimationPaused; - if (mIsAnimationPaused) { - illustrationView.pauseAnimation(); - } else { - illustrationView.resumeAnimation(); - } - }); - if (illustrationView != null && !TextUtils.isEmpty(mContentDescription)) { illustrationView.setContentDescription(mContentDescription); illustrationView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); @@ -171,12 +165,13 @@ public class IllustrationPreference extends Preference implements GroupSectionDi illustrationView.setCacheComposition(mCacheComposition); handleImageWithAnimation(illustrationView, illustrationFrame); + handleAnimationControl(illustrationView, illustrationFrame); handleImageFrameMaxHeight(backgroundView, illustrationView); if (mIsAutoScale) { illustrationView.setScaleType(mIsAutoScale - ? ImageView.ScaleType.CENTER_CROP - : ImageView.ScaleType.CENTER_INSIDE); + ? ImageView.ScaleType.CENTER_CROP + : ImageView.ScaleType.CENTER_INSIDE); } handleMiddleGroundView(middleGroundLayout); @@ -377,6 +372,7 @@ public class IllustrationPreference extends Preference implements GroupSectionDi final Drawable drawable = illustrationView.getDrawable(); if (drawable != null) { startAnimation(drawable); + mIsAnimatable = false; } } @@ -386,10 +382,12 @@ public class IllustrationPreference extends Preference implements GroupSectionDi final Drawable drawable = illustrationView.getDrawable(); if (drawable != null) { startAnimation(drawable); + mIsAnimatable = false; } else { // The lottie image from the raw folder also returns null because the ImageView // couldn't handle it now. startLottieAnimationWith(illustrationView, mImageUri); + mIsAnimatable = true; } } @@ -418,10 +416,12 @@ public class IllustrationPreference extends Preference implements GroupSectionDi final Drawable drawable = illustrationView.getDrawable(); if (drawable != null) { startAnimation(drawable); + mIsAnimatable = false; } else { // The lottie image from the raw folder also returns null because the ImageView // couldn't handle it now. startLottieAnimationWith(illustrationView, mImageResId); + mIsAnimatable = true; } } } @@ -459,6 +459,60 @@ public class IllustrationPreference extends Preference implements GroupSectionDi ((Animatable) drawable).start(); } + private void handleAnimationControl(LottieAnimationView illustrationView, + ViewGroup container) { + if (mIsAnimatable) { + // TODO(b/397340540): list out pages having illustration without a content description. + if (TextUtils.isEmpty(mContentDescription)) { + Log.w(TAG, "Illustration should have a content description. preference key = " + + getKey()); + } + // Enable pause and resume abilities to animation only + container.setOnClickListener(v -> { + mIsAnimationPaused = !mIsAnimationPaused; + if (mIsAnimationPaused) { + illustrationView.pauseAnimation(); + } else { + illustrationView.resumeAnimation(); + } + updateAccessibilityAction(container); + }); + + updateAccessibilityAction(container); + } + } + + private void updateAccessibilityAction(ViewGroup container) { + // Setting the state of animation + container.setStateDescription(getStateDescriptionForAnimation()); + container.setAccessibilityDelegate(new View.AccessibilityDelegate() { + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + final AccessibilityAction clickAction = new AccessibilityAction( + AccessibilityNodeInfo.ACTION_CLICK, + getActionLabelForAnimation()); + info.addAction(clickAction); + } + }); + } + + private String getActionLabelForAnimation() { + if (mIsAnimationPaused) { + return getContext().getString(R.string.settingslib_action_label_resume); + } else { + return getContext().getString(R.string.settingslib_action_label_pause); + } + } + + private String getStateDescriptionForAnimation() { + if (mIsAnimationPaused) { + return getContext().getString(R.string.settingslib_state_animation_paused); + } else { + return getContext().getString(R.string.settingslib_state_animation_playing); + } + } + private static void startLottieAnimationWith(LottieAnimationView illustrationView, Uri imageUri) { final InputStream inputStream = @@ -514,15 +568,20 @@ public class IllustrationPreference extends Preference implements GroupSectionDi mIsAutoScale = false; if (attrs != null) { TypedArray a = context.obtainStyledAttributes(attrs, - com.airbnb.lottie.R.styleable.LottieAnimationView, 0 /*defStyleAttr*/, 0 /*defStyleRes*/); - mImageResId = a.getResourceId(com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_rawRes, 0); + com.airbnb.lottie.R.styleable.LottieAnimationView, /* defStyleAttr= */ 0, + /* defStyleRes= */ 0); + mImageResId = a.getResourceId( + com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_rawRes, + /* defValue= */ 0); mCacheComposition = a.getBoolean( - com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_cacheComposition, true); + com.airbnb.lottie.R.styleable.LottieAnimationView_lottie_cacheComposition, + /* defValue= */ true); a = context.obtainStyledAttributes(attrs, - R.styleable.IllustrationPreference, 0 /*defStyleAttr*/, 0 /*defStyleRes*/); + R.styleable.IllustrationPreference, /* defStyleAttr= */ 0, + /* defStyleRes= */ 0); mLottieDynamicColor = a.getBoolean(R.styleable.IllustrationPreference_dynamicColor, - false); + /* defValue= */ false); a.recycle(); } diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml index dc5c9b297181..b6e80c784f10 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v35/themes.xml @@ -18,7 +18,7 @@ <resources> <style name="Theme.SettingsBase_v35" parent="Theme.SettingsBase_v33" > <item name="android:colorAccent">@color/settingslib_materialColorPrimary</item> - <item name="android:colorBackground">@color/settingslib_materialColorSurfaceContainerLowest</item> + <item name="android:colorBackground">@color/settingslib_materialColorSurfaceContainer</item> <item name="android:textColorPrimary">@color/settingslib_materialColorOnSurface</item> <item name="android:textColorSecondary">@color/settingslib_text_color_secondary</item> <item name="android:textColorTertiary">@color/settingslib_materialColorOutline</item> diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt index 6a0632073de9..a04fce7eeb86 100644 --- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt +++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsPreferenceGroupAdapter.kt @@ -47,7 +47,7 @@ open class SettingsPreferenceGroupAdapter(preferenceGroup: PreferenceGroup) : private val mHandler = Handler(Looper.getMainLooper()) - private val syncRunnable = Runnable { updatePreferences() } + private val syncRunnable = Runnable { updatePreferencesList() } init { val context = preferenceGroup.context @@ -64,7 +64,7 @@ open class SettingsPreferenceGroupAdapter(preferenceGroup: PreferenceGroup) : true, /* resolveRefs */ ) mLegacyBackgroundRes = outValue.resourceId - updatePreferences() + updatePreferencesList() } @SuppressLint("RestrictedApi") @@ -82,7 +82,7 @@ open class SettingsPreferenceGroupAdapter(preferenceGroup: PreferenceGroup) : updateBackground(holder, position) } - private fun updatePreferences() { + private fun updatePreferencesList() { val oldList = ArrayList(mRoundCornerMappingList) mRoundCornerMappingList = ArrayList() mappingPreferenceGroup(mRoundCornerMappingList, mPreferenceGroup) diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt index 1776d252e28b..1f4a48df55b0 100644 --- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt +++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsThemeHelper.kt @@ -50,10 +50,6 @@ object SettingsThemeHelper { } private fun tryInit(context: Context) { - if (expressiveThemeState != ExpressiveThemeState.UNKNOWN) { - return - } - expressiveThemeState = if ( (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) && diff --git a/packages/SettingsLib/Spa/spa/Android.bp b/packages/SettingsLib/Spa/spa/Android.bp index ac44a1be4cff..5aeea9c09f21 100644 --- a/packages/SettingsLib/Spa/spa/Android.bp +++ b/packages/SettingsLib/Spa/spa/Android.bp @@ -24,7 +24,9 @@ android_library { srcs: ["src/**/*.kt"], use_resource_processor: true, static_libs: [ + "MPAndroidChart", "SettingsLibColor", + "aconfig_settingstheme_exported_flags_java_lib", "androidx.compose.animation_animation", "androidx.compose.material3_material3", "androidx.compose.material_material-icons-extended", @@ -36,7 +38,6 @@ android_library { "androidx.navigation_navigation-compose", "com.google.android.material_material", "lottie_compose", - "MPAndroidChart", ], kotlincflags: [ "-Xjvm-default=all", diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts index 13966299b923..de1fa4ed20ed 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/spa/build.gradle.kts @@ -51,6 +51,7 @@ android { dependencies { api(project(":SettingsLibColor")) + api(project(":SettingsLib:SettingsTheme")) api("androidx.appcompat:appcompat:1.7.0") api("androidx.compose.material3:material3:1.4.0-alpha05") api("androidx.compose.material:material-icons-extended") diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt index f948d5163177..badf7aeb97c5 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsTheme.kt @@ -22,6 +22,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import com.android.settingslib.spa.framework.util.SystemProperties +import com.android.settingslib.widget.theme.flags.Flags /** * The Material 3 Theme for Settings. @@ -42,5 +43,7 @@ fun SettingsTheme(content: @Composable () -> Unit) { } } -val isSpaExpressiveEnabled - by lazy { SystemProperties.getBoolean("is_expressive_design_enabled", false) } +val isSpaExpressiveEnabled by lazy { + SystemProperties.getBoolean("is_expressive_design_enabled", false) || + Flags.isExpressiveDesignEnabled() +} diff --git a/packages/SettingsLib/Spa/tests/Android.bp b/packages/SettingsLib/Spa/tests/Android.bp index 871449e9d803..315b4009110e 100644 --- a/packages/SettingsLib/Spa/tests/Android.bp +++ b/packages/SettingsLib/Spa/tests/Android.bp @@ -30,10 +30,14 @@ android_test { static_libs: [ "SpaLib", "SpaLibTestUtils", + "aconfig_settingstheme_exported_flags_java_lib", "androidx.compose.runtime_runtime", "androidx.test.ext.junit", "androidx.test.runner", + "flag-junit", + "flag-junit-base", "mockito-target-minus-junit4", + "platform-test-annotations", ], kotlincflags: ["-Xjvm-default=all"], sdk_version: "current", diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/button/ActionButtonsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/button/ActionButtonsTest.kt index 8d9bac64b078..bab02b0753a9 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/button/ActionButtonsTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/button/ActionButtonsTest.kt @@ -16,6 +16,8 @@ package com.android.settingslib.spa.widget.button +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.flag.junit.DeviceFlagsValueProvider import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.Launch import androidx.compose.material.icons.outlined.Close @@ -28,6 +30,7 @@ import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settingslib.widget.theme.flags.Flags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED import com.google.common.truth.Truth.assertThat import org.junit.Rule import org.junit.Test @@ -37,6 +40,8 @@ import org.junit.runner.RunWith class ActionButtonsTest { @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @Test fun button_displayed() { @@ -54,6 +59,7 @@ class ActionButtonsTest { composeTestRule.onNodeWithText("Open").assertIsDisplayed() } + @RequiresFlagsDisabled(FLAG_IS_EXPRESSIVE_DESIGN_ENABLED) @Test fun button_clickable() { var clicked by mutableStateOf(false) diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt index 0a4f0d937600..89206baed6f7 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBarTest.kt @@ -16,6 +16,8 @@ package com.android.settingslib.spa.widget.scaffold +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.flag.junit.DeviceFlagsValueProvider import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -52,6 +54,7 @@ import androidx.compose.ui.text.TextStyle import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settingslib.spa.testutils.rootWidth import com.android.settingslib.spa.testutils.setContentForSizeAssertions +import com.android.settingslib.widget.theme.flags.Flags.FLAG_IS_EXPRESSIVE_DESIGN_ENABLED import com.google.common.truth.Truth.assertThat import org.junit.Rule import org.junit.Test @@ -62,6 +65,8 @@ import org.junit.runner.RunWith class CustomizedAppBarTest { @get:Rule val rule = createComposeRule() + @get:Rule + val mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() @Test fun smallTopAppBar_expandsToScreen() { @@ -97,6 +102,7 @@ class CustomizedAppBarTest { assertThat(textStyle).isEqualTo(expectedTextStyle) } + @RequiresFlagsDisabled(FLAG_IS_EXPRESSIVE_DESIGN_ENABLED) @Test fun smallTopAppBar_contentColor() { var titleColor: Color = Color.Unspecified diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig index d94450b1cabd..a029f56cf1d7 100644 --- a/packages/SettingsLib/aconfig/settingslib.aconfig +++ b/packages/SettingsLib/aconfig/settingslib.aconfig @@ -26,14 +26,14 @@ flag { name: "enable_le_audio_sharing" namespace: "pixel_cross_device_control" description: "Gates whether to enable LE audio sharing" - bug: "323125723" + bug: "388674074" } flag { name: "enable_le_audio_qr_code_private_broadcast_sharing" namespace: "pixel_cross_device_control" description: "Gates whether to enable LE audio private broadcast sharing via QR code" - bug: "323125723" + bug: "388674074" } flag { @@ -229,3 +229,23 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "adopt_primary_group_management_api_v2" + namespace: "cross_device_experiences" + description: "Adopt more Bluetooth LE broadcast primary group management APIs post launch" + bug: "381946931" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "promote_audio_sharing_for_second_auto_connected_lea_device" + namespace: "cross_device_experiences" + description: "Show audio sharing promote notification or dialog when the second lea device is auto connected" + bug: "395786392" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml new file mode 100644 index 000000000000..bd2fad2fedc0 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_1x_mobiledata_updated.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="12.88dp" + android:viewportWidth="13.53" + android:viewportHeight="10.25"> + <path + android:pathData="M3.738,10.252C3.468,10.252 3.234,10.154 3.038,9.958C2.847,9.757 2.751,9.522 2.751,9.251L2.751,2.587L1.372,3.497C1.167,3.628 0.943,3.672 0.7,3.63C0.462,3.588 0.276,3.467 0.14,3.266C0.01,3.065 -0.032,2.844 0.014,2.601C0.066,2.358 0.192,2.172 0.392,2.041L3.185,0.2C3.265,0.149 3.344,0.104 3.423,0.067C3.507,0.025 3.619,0.004 3.759,0.004C4.03,0.004 4.259,0.102 4.445,0.298C4.637,0.494 4.732,0.734 4.732,1.019L4.732,9.251C4.732,9.522 4.634,9.757 4.438,9.958C4.242,10.154 4.009,10.252 3.738,10.252ZM12.582,10.245C12.391,10.245 12.218,10.194 12.064,10.091C11.915,9.984 11.796,9.848 11.707,9.685L9.803,6.038L9.593,5.961L7.332,1.411C7.136,1.084 7.127,0.769 7.304,0.466C7.482,0.163 7.755,0.011 8.123,0.011C8.301,0.011 8.466,0.065 8.62,0.172C8.779,0.279 8.903,0.415 8.991,0.578L10.783,4.015L11.014,4.05L13.373,8.796C13.569,9.132 13.581,9.459 13.408,9.776C13.236,10.089 12.96,10.245 12.582,10.245ZM7.92,10.238C7.57,10.238 7.309,10.089 7.136,9.79C6.968,9.491 6.978,9.186 7.164,8.873L9.621,4.008L9.817,4.008L11.63,0.557C11.719,0.398 11.836,0.27 11.98,0.172C12.125,0.069 12.288,0.018 12.47,0.018C12.816,0.018 13.075,0.163 13.247,0.452C13.42,0.741 13.411,1.047 13.219,1.369L10.909,5.982L10.762,5.989L8.781,9.713C8.697,9.867 8.578,9.993 8.424,10.091C8.27,10.189 8.102,10.238 7.92,10.238Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml new file mode 100644 index 000000000000..8e632e69a56e --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_3g_mobiledata_updated.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="12.21dp" + android:viewportWidth="14.51" + android:viewportHeight="10.42"> + <path + android:pathData="M2.827,10.416C2.225,10.416 1.726,10.311 1.329,10.101C0.937,9.891 0.629,9.606 0.405,9.247C0.181,8.888 0.051,8.58 0.013,8.323C-0.019,8.066 0.023,7.849 0.139,7.672C0.256,7.49 0.415,7.371 0.615,7.315C0.816,7.254 1.003,7.259 1.175,7.329C1.353,7.394 1.481,7.495 1.56,7.63C1.644,7.765 1.733,7.922 1.826,8.099C1.92,8.272 2.041,8.416 2.19,8.533C2.34,8.65 2.533,8.708 2.771,8.708C3.089,8.708 3.343,8.615 3.534,8.428C3.726,8.237 3.821,7.959 3.821,7.595L3.821,6.888C3.821,6.529 3.726,6.256 3.534,6.069C3.348,5.882 3.077,5.789 2.722,5.789L2.456,5.789C2.251,5.789 2.071,5.714 1.917,5.565C1.768,5.416 1.693,5.236 1.693,5.026C1.693,4.816 1.768,4.636 1.917,4.487C2.067,4.338 2.244,4.263 2.449,4.263L2.666,4.263C2.984,4.263 3.222,4.177 3.38,4.004C3.544,3.831 3.625,3.558 3.625,3.185L3.625,2.618C3.625,2.315 3.544,2.084 3.38,1.925C3.217,1.766 2.998,1.687 2.722,1.687C2.531,1.687 2.37,1.729 2.239,1.813C2.109,1.892 1.999,2.004 1.91,2.149C1.822,2.294 1.738,2.427 1.658,2.548C1.579,2.665 1.453,2.756 1.28,2.821C1.108,2.882 0.926,2.882 0.734,2.821C0.543,2.756 0.391,2.632 0.279,2.45C0.172,2.268 0.142,2.049 0.188,1.792C0.24,1.531 0.384,1.248 0.622,0.945C0.86,0.642 1.159,0.408 1.518,0.245C1.882,0.082 2.326,0 2.848,0C3.67,0 4.323,0.215 4.808,0.644C5.294,1.069 5.536,1.636 5.536,2.345L5.536,2.8C5.536,3.332 5.417,3.768 5.179,4.109C4.941,4.445 4.598,4.69 4.15,4.844L4.15,4.9C4.678,5.017 5.086,5.259 5.375,5.628C5.669,5.992 5.816,6.484 5.816,7.105L5.816,7.679C5.816,8.514 5.55,9.179 5.018,9.674C4.491,10.169 3.761,10.416 2.827,10.416ZM10.943,10.416C9.819,10.411 8.92,10.031 8.248,9.275C7.581,8.514 7.247,7.406 7.247,5.95L7.247,4.417C7.247,2.975 7.588,1.878 8.269,1.127C8.951,0.371 9.863,-0.005 11.006,0C11.52,0 11.954,0.075 12.308,0.224C12.668,0.369 12.973,0.576 13.225,0.847C13.482,1.113 13.659,1.374 13.757,1.631C13.855,1.883 13.862,2.121 13.778,2.345C13.694,2.569 13.55,2.732 13.344,2.835C13.144,2.938 12.948,2.968 12.756,2.926C12.565,2.884 12.416,2.802 12.308,2.681C12.201,2.555 12.091,2.422 11.979,2.282C11.867,2.142 11.727,2.032 11.559,1.953C11.391,1.869 11.191,1.827 10.957,1.827C10.439,1.822 10.024,2.011 9.711,2.394C9.403,2.777 9.249,3.358 9.249,4.137L9.249,6.293C9.249,7.063 9.408,7.644 9.725,8.036C10.047,8.428 10.467,8.624 10.985,8.624C11.489,8.624 11.884,8.477 12.168,8.183C12.453,7.889 12.607,7.474 12.63,6.937L12.63,6.265L11.657,6.265C11.452,6.265 11.275,6.188 11.125,6.034C10.976,5.875 10.901,5.689 10.901,5.474C10.901,5.255 10.978,5.068 11.132,4.914C11.291,4.755 11.48,4.676 11.699,4.676L13.666,4.676C13.9,4.676 14.098,4.755 14.261,4.914C14.425,5.073 14.509,5.269 14.513,5.502L14.513,6.538C14.513,7.77 14.191,8.724 13.547,9.401C12.908,10.078 12.04,10.416 10.943,10.416Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml new file mode 100644 index 000000000000..bba359e8b238 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_4g_lte_mobiledata_updated.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="34dp" + android:height="14.07dp" + android:viewportWidth="27.29" + android:viewportHeight="11.29"> + <path + android:pathData="M4.552,11.195C4.286,11.195 4.058,11.099 3.866,10.908C3.68,10.717 3.586,10.488 3.586,10.222L3.586,8.171L3.74,7.891L3.74,2.823L4.72,3.53L3.712,3.53L1.808,7.366L4.37,7.366L4.797,7.275L5.777,7.275C6.015,7.275 6.218,7.359 6.386,7.527C6.554,7.695 6.638,7.898 6.638,8.136C6.638,8.369 6.554,8.57 6.386,8.738C6.218,8.906 6.015,8.99 5.777,8.99L1.192,8.99C0.856,8.99 0.572,8.88 0.338,8.661C0.11,8.442 -0.005,8.169 -0.005,7.842C-0.005,7.683 0.016,7.569 0.058,7.499C0.1,7.424 0.142,7.35 0.184,7.275L3.124,1.633C3.222,1.446 3.374,1.283 3.579,1.143C3.789,1.003 4.013,0.933 4.251,0.933C4.606,0.933 4.905,1.061 5.147,1.318C5.39,1.57 5.511,1.876 5.511,2.235L5.511,10.222C5.511,10.488 5.416,10.717 5.224,10.908C5.038,11.099 4.814,11.195 4.552,11.195ZM11.303,11.286C10.179,11.281 9.28,10.901 8.608,10.145C7.941,9.384 7.607,8.276 7.607,6.82L7.607,5.287C7.607,3.845 7.948,2.748 8.629,1.997C9.311,1.241 10.223,0.865 11.366,0.87C11.88,0.87 12.314,0.945 12.668,1.094C13.028,1.239 13.333,1.446 13.585,1.717C13.842,1.983 14.019,2.244 14.117,2.501C14.215,2.753 14.222,2.991 14.138,3.215C14.054,3.439 13.91,3.602 13.704,3.705C13.504,3.808 13.308,3.838 13.116,3.796C12.925,3.754 12.776,3.672 12.668,3.551C12.561,3.425 12.451,3.292 12.339,3.152C12.227,3.012 12.087,2.902 11.919,2.823C11.751,2.739 11.551,2.697 11.317,2.697C10.799,2.692 10.384,2.881 10.071,3.264C9.763,3.647 9.609,4.228 9.609,5.007L9.609,7.163C9.609,7.933 9.768,8.514 10.085,8.906C10.407,9.298 10.827,9.494 11.345,9.494C11.849,9.494 12.244,9.347 12.528,9.053C12.813,8.759 12.967,8.344 12.99,7.807L12.99,7.135L12.017,7.135C11.812,7.135 11.635,7.058 11.485,6.904C11.336,6.745 11.261,6.559 11.261,6.344C11.261,6.125 11.338,5.938 11.492,5.784C11.651,5.625 11.84,5.546 12.059,5.546L14.026,5.546C14.26,5.546 14.458,5.625 14.621,5.784C14.785,5.943 14.869,6.139 14.873,6.372L14.873,7.408C14.873,8.64 14.551,9.594 13.907,10.271C13.268,10.948 12.4,11.286 11.303,11.286ZM16.641,6.09C16.434,6.09 16.256,6.016 16.108,5.867C15.962,5.719 15.89,5.543 15.89,5.338L15.89,0.689C15.89,0.501 15.957,0.34 16.091,0.206C16.226,0.069 16.385,0 16.57,0C16.758,0 16.919,0.069 17.053,0.206C17.187,0.34 17.255,0.501 17.255,0.689L17.255,4.83L18.54,4.83C18.713,4.83 18.863,4.892 18.989,5.015C19.115,5.138 19.178,5.286 19.178,5.46C19.178,5.631 19.115,5.779 18.989,5.905C18.863,6.028 18.713,6.09 18.54,6.09L16.641,6.09ZM20.979,6.166C20.792,6.166 20.63,6.098 20.496,5.964C20.365,5.827 20.299,5.664 20.299,5.477L20.299,0.731L21.664,0.731L21.664,5.477C21.664,5.664 21.597,5.827 21.462,5.964C21.328,6.098 21.167,6.166 20.979,6.166ZM19.648,1.331C19.474,1.331 19.324,1.27 19.198,1.147C19.075,1.023 19.014,0.876 19.014,0.706C19.014,0.532 19.075,0.384 19.198,0.26C19.324,0.137 19.474,0.076 19.648,0.076L22.306,0.076C22.48,0.076 22.628,0.137 22.751,0.26C22.877,0.384 22.941,0.532 22.941,0.706C22.941,0.876 22.877,1.023 22.751,1.147C22.628,1.27 22.48,1.331 22.306,1.331L19.648,1.331ZM24.553,6.09C24.346,6.09 24.168,6.016 24.019,5.867C23.874,5.719 23.801,5.543 23.801,5.338L23.801,0.823C23.801,0.619 23.874,0.444 24.019,0.298C24.168,0.15 24.346,0.076 24.553,0.076L26.59,0.076C26.763,0.076 26.912,0.137 27.035,0.26C27.161,0.384 27.224,0.531 27.224,0.701C27.224,0.872 27.161,1.019 27.035,1.142C26.912,1.266 26.763,1.327 26.59,1.327L25.158,1.327L25.158,4.838L26.657,4.838C26.831,4.838 26.979,4.9 27.102,5.023C27.225,5.146 27.287,5.293 27.287,5.464C27.287,5.635 27.225,5.782 27.102,5.905C26.979,6.028 26.831,6.09 26.657,6.09L24.553,6.09ZM24.637,3.595L24.637,2.444L26.3,2.444C26.46,2.444 26.595,2.5 26.707,2.612C26.822,2.724 26.88,2.86 26.88,3.02C26.88,3.177 26.822,3.312 26.707,3.427C26.595,3.539 26.46,3.595 26.3,3.595L24.637,3.595Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml new file mode 100644 index 000000000000..cb6fd50a07ea --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_4g_lte_plus_mobiledata_updated.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="34dp" + android:height="11.93dp" + android:viewportWidth="32.18" + android:viewportHeight="11.29"> + <path + android:pathData="M4.552,11.195C4.286,11.195 4.058,11.099 3.866,10.908C3.68,10.717 3.586,10.488 3.586,10.222L3.586,8.171L3.74,7.891L3.74,2.823L4.72,3.53L3.712,3.53L1.808,7.366L4.37,7.366L4.797,7.275L5.777,7.275C6.015,7.275 6.218,7.359 6.386,7.527C6.554,7.695 6.638,7.898 6.638,8.136C6.638,8.369 6.554,8.57 6.386,8.738C6.218,8.906 6.015,8.99 5.777,8.99L1.192,8.99C0.856,8.99 0.572,8.88 0.338,8.661C0.11,8.442 -0.005,8.169 -0.005,7.842C-0.005,7.683 0.016,7.569 0.058,7.499C0.1,7.424 0.142,7.35 0.184,7.275L3.124,1.633C3.222,1.446 3.374,1.283 3.579,1.143C3.789,1.003 4.013,0.933 4.251,0.933C4.606,0.933 4.905,1.061 5.147,1.318C5.39,1.57 5.511,1.876 5.511,2.235L5.511,10.222C5.511,10.488 5.416,10.717 5.224,10.908C5.038,11.099 4.814,11.195 4.552,11.195ZM11.303,11.286C10.179,11.281 9.28,10.901 8.608,10.145C7.941,9.384 7.607,8.276 7.607,6.82L7.607,5.287C7.607,3.845 7.948,2.748 8.629,1.997C9.311,1.241 10.223,0.865 11.366,0.87C11.88,0.87 12.314,0.945 12.668,1.094C13.028,1.239 13.333,1.446 13.585,1.717C13.842,1.983 14.019,2.244 14.117,2.501C14.215,2.753 14.222,2.991 14.138,3.215C14.054,3.439 13.91,3.602 13.704,3.705C13.504,3.808 13.308,3.838 13.116,3.796C12.925,3.754 12.776,3.672 12.668,3.551C12.561,3.425 12.451,3.292 12.339,3.152C12.227,3.012 12.087,2.902 11.919,2.823C11.751,2.739 11.551,2.697 11.317,2.697C10.799,2.692 10.384,2.881 10.071,3.264C9.763,3.647 9.609,4.228 9.609,5.007L9.609,7.163C9.609,7.933 9.768,8.514 10.085,8.906C10.407,9.298 10.827,9.494 11.345,9.494C11.849,9.494 12.244,9.347 12.528,9.053C12.813,8.759 12.967,8.344 12.99,7.807L12.99,7.135L12.017,7.135C11.812,7.135 11.635,7.058 11.485,6.904C11.336,6.745 11.261,6.559 11.261,6.344C11.261,6.125 11.338,5.938 11.492,5.784C11.651,5.625 11.84,5.546 12.059,5.546L14.026,5.546C14.26,5.546 14.458,5.625 14.621,5.784C14.785,5.943 14.869,6.139 14.873,6.372L14.873,7.408C14.873,8.64 14.551,9.594 13.907,10.271C13.268,10.948 12.4,11.286 11.303,11.286ZM16.641,6.09C16.434,6.09 16.256,6.016 16.108,5.867C15.962,5.719 15.89,5.543 15.89,5.338L15.89,0.689C15.89,0.501 15.957,0.34 16.091,0.206C16.226,0.069 16.385,0 16.57,0C16.758,0 16.919,0.069 17.053,0.206C17.187,0.34 17.255,0.501 17.255,0.689L17.255,4.83L18.54,4.83C18.713,4.83 18.863,4.892 18.989,5.015C19.115,5.138 19.178,5.286 19.178,5.46C19.178,5.631 19.115,5.779 18.989,5.905C18.863,6.028 18.713,6.09 18.54,6.09L16.641,6.09ZM20.979,6.166C20.792,6.166 20.63,6.098 20.496,5.964C20.365,5.827 20.299,5.664 20.299,5.477L20.299,0.731L21.664,0.731L21.664,5.477C21.664,5.664 21.597,5.827 21.462,5.964C21.328,6.098 21.167,6.166 20.979,6.166ZM19.648,1.331C19.474,1.331 19.324,1.27 19.198,1.147C19.075,1.023 19.014,0.876 19.014,0.706C19.014,0.532 19.075,0.384 19.198,0.26C19.324,0.137 19.474,0.076 19.648,0.076L22.306,0.076C22.48,0.076 22.628,0.137 22.751,0.26C22.877,0.384 22.941,0.532 22.941,0.706C22.941,0.876 22.877,1.023 22.751,1.147C22.628,1.27 22.48,1.331 22.306,1.331L19.648,1.331ZM24.553,6.09C24.346,6.09 24.168,6.016 24.019,5.867C23.874,5.719 23.801,5.543 23.801,5.338L23.801,0.823C23.801,0.619 23.874,0.444 24.019,0.298C24.168,0.15 24.346,0.076 24.553,0.076L26.59,0.076C26.763,0.076 26.912,0.137 27.035,0.26C27.161,0.384 27.224,0.531 27.224,0.701C27.224,0.872 27.161,1.019 27.035,1.142C26.912,1.266 26.763,1.327 26.59,1.327L25.158,1.327L25.158,4.838L26.657,4.838C26.831,4.838 26.979,4.9 27.102,5.023C27.225,5.146 27.287,5.293 27.287,5.464C27.287,5.635 27.225,5.782 27.102,5.905C26.979,6.028 26.831,6.09 26.657,6.09L24.553,6.09ZM24.637,3.595L24.637,2.444L26.3,2.444C26.46,2.444 26.595,2.5 26.707,2.612C26.822,2.724 26.88,2.86 26.88,3.02C26.88,3.177 26.822,3.312 26.707,3.427C26.595,3.539 26.46,3.595 26.3,3.595L24.637,3.595Z" + android:fillColor="#000"/> + <path + android:pathData="M30.101,5.346C29.923,5.346 29.768,5.282 29.637,5.154C29.509,5.023 29.445,4.867 29.445,4.686L29.445,1.742C29.445,1.561 29.509,1.406 29.637,1.278C29.768,1.147 29.923,1.082 30.101,1.082C30.28,1.082 30.433,1.147 30.561,1.278C30.689,1.406 30.753,1.561 30.753,1.742L30.753,4.686C30.753,4.867 30.689,5.023 30.561,5.154C30.433,5.282 30.28,5.346 30.101,5.346ZM28.677,3.858C28.499,3.858 28.345,3.795 28.217,3.67C28.089,3.542 28.025,3.39 28.025,3.214C28.025,3.038 28.089,2.887 28.217,2.762C28.345,2.634 28.499,2.57 28.677,2.57L31.525,2.57C31.704,2.57 31.857,2.634 31.985,2.762C32.113,2.887 32.177,3.038 32.177,3.214C32.177,3.39 32.113,3.542 31.985,3.67C31.857,3.795 31.704,3.858 31.525,3.858L28.677,3.858Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml new file mode 100644 index 000000000000..562bcaf2fdba --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_4g_mobiledata_updated.xml @@ -0,0 +1,25 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="19dp" + android:height="13.31dp" + android:viewportWidth="14.88" + android:viewportHeight="10.42"> + <path + android:pathData="M4.552,10.325C4.286,10.325 4.058,10.229 3.866,10.038C3.68,9.847 3.586,9.618 3.586,9.352L3.586,7.301L3.74,7.021L3.74,1.953L4.72,2.66L3.712,2.66L1.808,6.496L4.37,6.496L4.797,6.405L5.777,6.405C6.015,6.405 6.218,6.489 6.386,6.657C6.554,6.825 6.638,7.028 6.638,7.266C6.638,7.499 6.554,7.7 6.386,7.868C6.218,8.036 6.015,8.12 5.777,8.12L1.192,8.12C0.856,8.12 0.572,8.01 0.338,7.791C0.11,7.572 -0.005,7.299 -0.005,6.972C-0.005,6.813 0.016,6.699 0.058,6.629C0.1,6.554 0.142,6.48 0.184,6.405L3.124,0.763C3.222,0.576 3.374,0.413 3.579,0.273C3.789,0.133 4.013,0.063 4.251,0.063C4.606,0.063 4.905,0.191 5.147,0.448C5.39,0.7 5.511,1.006 5.511,1.365L5.511,9.352C5.511,9.618 5.416,9.847 5.224,10.038C5.038,10.229 4.814,10.325 4.552,10.325ZM11.303,10.416C10.179,10.411 9.28,10.031 8.608,9.275C7.941,8.514 7.607,7.406 7.607,5.95L7.607,4.417C7.607,2.975 7.948,1.878 8.629,1.127C9.311,0.371 10.223,-0.005 11.366,0C11.88,0 12.314,0.075 12.668,0.224C13.028,0.369 13.333,0.576 13.585,0.847C13.842,1.113 14.019,1.374 14.117,1.631C14.215,1.883 14.222,2.121 14.138,2.345C14.054,2.569 13.91,2.732 13.704,2.835C13.504,2.938 13.308,2.968 13.116,2.926C12.925,2.884 12.776,2.802 12.668,2.681C12.561,2.555 12.451,2.422 12.339,2.282C12.227,2.142 12.087,2.032 11.919,1.953C11.751,1.869 11.551,1.827 11.317,1.827C10.799,1.822 10.384,2.011 10.071,2.394C9.763,2.777 9.609,3.358 9.609,4.137L9.609,6.293C9.609,7.063 9.768,7.644 10.085,8.036C10.407,8.428 10.827,8.624 11.345,8.624C11.849,8.624 12.244,8.477 12.528,8.183C12.813,7.889 12.967,7.474 12.99,6.937L12.99,6.265L12.017,6.265C11.812,6.265 11.635,6.188 11.485,6.034C11.336,5.875 11.261,5.689 11.261,5.474C11.261,5.255 11.338,5.068 11.492,4.914C11.651,4.755 11.84,4.676 12.059,4.676L14.026,4.676C14.26,4.676 14.458,4.755 14.621,4.914C14.785,5.073 14.869,5.269 14.873,5.502L14.873,6.538C14.873,7.77 14.551,8.724 13.907,9.401C13.268,10.078 12.4,10.416 11.303,10.416Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml new file mode 100644 index 000000000000..73e8994681c2 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_4g_plus_mobiledata_updated.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="23dp" + android:height="12.5dp" + android:viewportWidth="19.17" + android:viewportHeight="10.42"> + <path + android:pathData="M4.552,10.325C4.286,10.325 4.058,10.229 3.866,10.038C3.68,9.847 3.586,9.618 3.586,9.352L3.586,7.301L3.74,7.021L3.74,1.953L4.72,2.66L3.712,2.66L1.808,6.496L4.37,6.496L4.797,6.405L5.777,6.405C6.015,6.405 6.218,6.489 6.386,6.657C6.554,6.825 6.638,7.028 6.638,7.266C6.638,7.499 6.554,7.7 6.386,7.868C6.218,8.036 6.015,8.12 5.777,8.12L1.192,8.12C0.856,8.12 0.572,8.01 0.338,7.791C0.11,7.572 -0.005,7.299 -0.005,6.972C-0.005,6.813 0.016,6.699 0.058,6.629C0.1,6.554 0.142,6.48 0.184,6.405L3.124,0.763C3.222,0.576 3.374,0.413 3.579,0.273C3.789,0.133 4.013,0.063 4.251,0.063C4.606,0.063 4.905,0.191 5.147,0.448C5.39,0.7 5.511,1.006 5.511,1.365L5.511,9.352C5.511,9.618 5.416,9.847 5.224,10.038C5.038,10.229 4.814,10.325 4.552,10.325ZM11.303,10.416C10.179,10.411 9.28,10.031 8.608,9.275C7.941,8.514 7.607,7.406 7.607,5.95L7.607,4.417C7.607,2.975 7.948,1.878 8.629,1.127C9.311,0.371 10.223,-0.005 11.366,0C11.88,0 12.314,0.075 12.668,0.224C13.028,0.369 13.333,0.576 13.585,0.847C13.842,1.113 14.019,1.374 14.117,1.631C14.215,1.883 14.222,2.121 14.138,2.345C14.054,2.569 13.91,2.732 13.704,2.835C13.504,2.938 13.308,2.968 13.116,2.926C12.925,2.884 12.776,2.802 12.668,2.681C12.561,2.555 12.451,2.422 12.339,2.282C12.227,2.142 12.087,2.032 11.919,1.953C11.751,1.869 11.551,1.827 11.317,1.827C10.799,1.822 10.384,2.011 10.071,2.394C9.763,2.777 9.609,3.358 9.609,4.137L9.609,6.293C9.609,7.063 9.768,7.644 10.085,8.036C10.407,8.428 10.827,8.624 11.345,8.624C11.849,8.624 12.244,8.477 12.528,8.183C12.813,7.889 12.967,7.474 12.99,6.937L12.99,6.265L12.017,6.265C11.812,6.265 11.635,6.188 11.485,6.034C11.336,5.875 11.261,5.689 11.261,5.474C11.261,5.255 11.338,5.068 11.492,4.914C11.651,4.755 11.84,4.676 12.059,4.676L14.026,4.676C14.26,4.676 14.458,4.755 14.621,4.914C14.785,5.073 14.869,5.269 14.873,5.502L14.873,6.538C14.873,7.77 14.551,8.724 13.907,9.401C13.268,10.078 12.4,10.416 11.303,10.416Z" + android:fillColor="#000"/> + <path + android:pathData="M17.086,4.476C16.907,4.476 16.752,4.412 16.622,4.284C16.494,4.153 16.43,3.997 16.43,3.816L16.43,0.872C16.43,0.691 16.494,0.536 16.622,0.408C16.752,0.277 16.907,0.212 17.086,0.212C17.264,0.212 17.418,0.277 17.546,0.408C17.674,0.536 17.738,0.691 17.738,0.872L17.738,3.816C17.738,3.997 17.674,4.153 17.546,4.284C17.418,4.412 17.264,4.476 17.086,4.476ZM15.662,2.988C15.483,2.988 15.33,2.925 15.202,2.8C15.074,2.672 15.01,2.52 15.01,2.344C15.01,2.168 15.074,2.017 15.202,1.892C15.33,1.764 15.483,1.7 15.662,1.7L18.51,1.7C18.688,1.7 18.842,1.764 18.97,1.892C19.098,2.017 19.162,2.168 19.162,2.344C19.162,2.52 19.098,2.672 18.97,2.8C18.842,2.925 18.688,2.988 18.51,2.988L15.662,2.988Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml new file mode 100644 index 000000000000..c46da66a9183 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_5g_e_mobiledata_updated.xml @@ -0,0 +1,25 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="22.0dp" + android:height="12.57dp" + android:viewportHeight="11.21" + android:viewportWidth="19.62"> + + <path + android:fillColor="#000" + android:pathData="M2.573,11.206C1.99,11.206 1.502,11.094 1.11,10.87C0.718,10.641 0.436,10.364 0.263,10.037C0.091,9.706 0.002,9.4 -0.003,9.12C-0.007,8.84 0.058,8.616 0.193,8.448C0.333,8.275 0.499,8.168 0.69,8.126C0.882,8.079 1.057,8.089 1.215,8.154C1.379,8.219 1.502,8.315 1.586,8.441C1.675,8.567 1.75,8.716 1.81,8.889C1.871,9.062 1.971,9.202 2.111,9.309C2.251,9.412 2.429,9.463 2.643,9.463C2.947,9.463 3.203,9.363 3.413,9.162C3.623,8.961 3.763,8.663 3.833,8.266L4.008,7.272C4.074,6.899 4.029,6.609 3.875,6.404C3.726,6.199 3.5,6.096 3.196,6.096C3,6.096 2.825,6.143 2.671,6.236C2.522,6.325 2.401,6.43 2.307,6.551C2.181,6.672 2.03,6.752 1.852,6.789C1.675,6.826 1.488,6.81 1.292,6.74C1.045,6.651 0.865,6.497 0.753,6.278C0.641,6.054 0.62,5.804 0.69,5.529L1.593,1.98C1.677,1.672 1.831,1.429 2.055,1.252C2.284,1.075 2.557,0.986 2.874,0.986L5.674,0.986C5.964,0.986 6.195,1.089 6.367,1.294C6.54,1.495 6.601,1.733 6.549,2.008C6.517,2.213 6.412,2.388 6.234,2.533C6.062,2.673 5.875,2.743 5.674,2.743L3.056,2.743L2.433,5.13L2.475,5.137C2.676,4.955 2.905,4.815 3.161,4.717C3.418,4.614 3.7,4.563 4.008,4.563C4.727,4.563 5.268,4.836 5.632,5.382C6.001,5.923 6.111,6.628 5.961,7.496L5.814,8.336C5.656,9.274 5.299,9.988 4.743,10.478C4.188,10.963 3.465,11.206 2.573,11.206ZM10.577,11.206C9.392,11.206 8.515,10.795 7.945,9.974C7.381,9.153 7.229,8.009 7.49,6.544L7.749,5.039C8.006,3.606 8.498,2.54 9.226,1.84C9.959,1.14 10.883,0.79 11.998,0.79C12.535,0.79 12.995,0.879 13.377,1.056C13.76,1.229 14.059,1.46 14.273,1.749C14.488,2.038 14.612,2.314 14.644,2.575C14.677,2.832 14.644,3.053 14.546,3.24C14.453,3.427 14.313,3.567 14.126,3.66C13.94,3.749 13.753,3.774 13.566,3.737C13.384,3.695 13.244,3.606 13.146,3.471C13.048,3.336 12.941,3.2 12.824,3.065C12.708,2.925 12.57,2.815 12.411,2.736C12.257,2.657 12.068,2.617 11.844,2.617C11.35,2.617 10.918,2.808 10.549,3.191C10.185,3.569 9.936,4.141 9.8,4.906L9.422,7.048C9.287,7.813 9.348,8.399 9.604,8.805C9.861,9.211 10.248,9.414 10.766,9.414C11.256,9.414 11.665,9.267 11.991,8.973C12.318,8.679 12.54,8.264 12.656,7.727L12.775,7.055L11.893,7.055C11.665,7.055 11.48,6.964 11.34,6.782C11.205,6.6 11.158,6.385 11.2,6.138C11.233,5.951 11.326,5.795 11.48,5.669C11.639,5.538 11.809,5.473 11.991,5.473L13.979,5.473C14.25,5.473 14.462,5.566 14.616,5.753C14.775,5.94 14.831,6.168 14.784,6.439L14.595,7.489C14.376,8.702 13.916,9.626 13.216,10.261C12.521,10.891 11.641,11.206 10.577,11.206ZM16.001,6.01C15.799,6.01 15.637,5.937 15.514,5.792C15.39,5.643 15.346,5.47 15.379,5.271L16.181,0.735C16.218,0.53 16.321,0.357 16.492,0.214C16.666,0.068 16.856,-0.004 17.063,-0.004L18.983,-0.004C19.187,-0.004 19.351,0.068 19.474,0.214C19.597,0.36 19.642,0.529 19.609,0.722C19.581,0.868 19.505,0.992 19.382,1.096C19.259,1.197 19.126,1.247 18.983,1.247L17.462,1.247L16.841,4.758L18.21,4.758C18.414,4.758 18.577,4.831 18.697,4.977C18.82,5.122 18.865,5.292 18.832,5.485C18.806,5.631 18.732,5.755 18.609,5.859C18.486,5.96 18.353,6.01 18.21,6.01L16.001,6.01ZM16.526,3.515L16.732,2.364L18.281,2.364C18.472,2.364 18.623,2.432 18.735,2.566C18.847,2.698 18.888,2.853 18.857,3.032C18.832,3.167 18.762,3.281 18.647,3.377C18.535,3.469 18.413,3.515 18.281,3.515L16.526,3.515Z" /> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml new file mode 100644 index 000000000000..66787b0a7594 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_5g_mobiledata_updated.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="12.28dp" + android:viewportWidth="14.42" + android:viewportHeight="10.42"> + <path + android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml new file mode 100644 index 000000000000..5ba3c98028a2 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_default_updated.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="22dp" + android:height="11.63dp" + android:viewportWidth="19.71" + android:viewportHeight="10.42"> + <path + android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z" + android:fillColor="#000"/> + <path + android:pathData="M17.636,4.476C17.457,4.476 17.302,4.412 17.172,4.284C17.044,4.153 16.98,3.997 16.98,3.816L16.98,0.872C16.98,0.691 17.044,0.536 17.172,0.408C17.302,0.277 17.457,0.212 17.636,0.212C17.814,0.212 17.968,0.277 18.096,0.408C18.224,0.536 18.288,0.691 18.288,0.872L18.288,3.816C18.288,3.997 18.224,4.153 18.096,4.284C17.968,4.412 17.814,4.476 17.636,4.476ZM16.212,2.988C16.033,2.988 15.88,2.925 15.752,2.8C15.624,2.672 15.56,2.52 15.56,2.344C15.56,2.168 15.624,2.017 15.752,1.892C15.88,1.764 16.033,1.7 16.212,1.7L19.06,1.7C19.238,1.7 19.392,1.764 19.52,1.892C19.648,2.017 19.712,2.168 19.712,2.344C19.712,2.52 19.648,2.672 19.52,2.8C19.392,2.925 19.238,2.988 19.06,2.988L16.212,2.988Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml new file mode 100644 index 000000000000..5ba3c98028a2 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_5g_plus_mobiledata_updated.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="22dp" + android:height="11.63dp" + android:viewportWidth="19.71" + android:viewportHeight="10.42"> + <path + android:pathData="M2.807,10.416C2.247,10.416 1.774,10.325 1.386,10.143C0.999,9.956 0.684,9.704 0.441,9.387C0.199,9.065 0.056,8.745 0.014,8.428C-0.028,8.111 0.014,7.859 0.14,7.672C0.271,7.485 0.439,7.366 0.644,7.315C0.85,7.259 1.036,7.266 1.204,7.336C1.372,7.406 1.494,7.506 1.568,7.637C1.643,7.763 1.727,7.912 1.82,8.085C1.914,8.253 2.03,8.393 2.17,8.505C2.315,8.617 2.504,8.673 2.737,8.673C3.055,8.673 3.309,8.57 3.5,8.365C3.696,8.16 3.794,7.849 3.794,7.434L3.794,6.461C3.794,6.083 3.701,5.796 3.514,5.6C3.332,5.399 3.092,5.299 2.793,5.299C2.593,5.299 2.427,5.341 2.296,5.425C2.166,5.509 2.054,5.605 1.96,5.712C1.858,5.819 1.715,5.901 1.533,5.957C1.351,6.008 1.148,6.001 0.924,5.936C0.682,5.861 0.49,5.714 0.35,5.495C0.215,5.271 0.159,5.035 0.182,4.788L0.455,1.281C0.483,0.987 0.614,0.733 0.847,0.518C1.081,0.303 1.347,0.196 1.645,0.196L4.515,0.196C4.758,0.196 4.966,0.282 5.138,0.455C5.316,0.628 5.404,0.833 5.404,1.071C5.404,1.314 5.316,1.521 5.138,1.694C4.966,1.867 4.758,1.953 4.515,1.953L2.044,1.953L1.841,4.34L1.897,4.354C2.07,4.172 2.285,4.03 2.541,3.927C2.803,3.824 3.094,3.773 3.416,3.773C4.126,3.773 4.697,4.02 5.131,4.515C5.565,5.005 5.782,5.677 5.782,6.531L5.782,7.378C5.782,8.33 5.516,9.074 4.984,9.611C4.452,10.148 3.727,10.416 2.807,10.416ZM10.853,10.416C9.729,10.411 8.83,10.031 8.158,9.275C7.491,8.514 7.157,7.406 7.157,5.95L7.157,4.417C7.157,2.975 7.498,1.878 8.179,1.127C8.861,0.371 9.773,-0.005 10.916,0C11.43,0 11.864,0.075 12.218,0.224C12.578,0.369 12.883,0.576 13.135,0.847C13.392,1.113 13.569,1.374 13.667,1.631C13.765,1.883 13.772,2.121 13.688,2.345C13.604,2.569 13.46,2.732 13.254,2.835C13.054,2.938 12.858,2.968 12.666,2.926C12.475,2.884 12.326,2.802 12.218,2.681C12.111,2.555 12.001,2.422 11.889,2.282C11.777,2.142 11.637,2.032 11.469,1.953C11.301,1.869 11.101,1.827 10.867,1.827C10.349,1.822 9.934,2.011 9.621,2.394C9.313,2.777 9.159,3.358 9.159,4.137L9.159,6.293C9.159,7.063 9.318,7.644 9.635,8.036C9.957,8.428 10.377,8.624 10.895,8.624C11.399,8.624 11.794,8.477 12.078,8.183C12.363,7.889 12.517,7.474 12.54,6.937L12.54,6.265L11.567,6.265C11.362,6.265 11.185,6.188 11.035,6.034C10.886,5.875 10.811,5.689 10.811,5.474C10.811,5.255 10.888,5.068 11.042,4.914C11.201,4.755 11.39,4.676 11.609,4.676L13.576,4.676C13.81,4.676 14.008,4.755 14.171,4.914C14.335,5.073 14.419,5.269 14.423,5.502L14.423,6.538C14.423,7.77 14.101,8.724 13.457,9.401C12.818,10.078 11.95,10.416 10.853,10.416Z" + android:fillColor="#000"/> + <path + android:pathData="M17.636,4.476C17.457,4.476 17.302,4.412 17.172,4.284C17.044,4.153 16.98,3.997 16.98,3.816L16.98,0.872C16.98,0.691 17.044,0.536 17.172,0.408C17.302,0.277 17.457,0.212 17.636,0.212C17.814,0.212 17.968,0.277 18.096,0.408C18.224,0.536 18.288,0.691 18.288,0.872L18.288,3.816C18.288,3.997 18.224,4.153 18.096,4.284C17.968,4.412 17.814,4.476 17.636,4.476ZM16.212,2.988C16.033,2.988 15.88,2.925 15.752,2.8C15.624,2.672 15.56,2.52 15.56,2.344C15.56,2.168 15.624,2.017 15.752,1.892C15.88,1.764 16.033,1.7 16.212,1.7L19.06,1.7C19.238,1.7 19.392,1.764 19.52,1.892C19.648,2.017 19.712,2.168 19.712,2.344C19.712,2.52 19.648,2.672 19.52,2.8C19.392,2.925 19.238,2.988 19.06,2.988L16.212,2.988Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml b/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml new file mode 100644 index 000000000000..14db82614ad1 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_carrier_wifi_updated.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="19.0dp" + android:height="12.38dp" + android:viewportHeight="10.26" + android:viewportWidth="15.75"> + + <path + android:fillColor="#000" + android:pathData="M2.864,10.259C2.598,10.259 2.358,10.168 2.143,9.986C1.929,9.804 1.793,9.589 1.737,9.342L0.036,1.208C-0.043,0.877 0.013,0.594 0.204,0.361C0.4,0.128 0.657,0.011 0.974,0.011C1.208,0.011 1.418,0.093 1.604,0.256C1.791,0.419 1.908,0.611 1.954,0.83L2.885,5.828L3.039,6.92L3.088,6.92L3.249,5.828L4.278,0.851C4.325,0.622 4.446,0.424 4.642,0.256C4.843,0.088 5.065,0.004 5.307,0.004C5.55,0.004 5.769,0.088 5.965,0.256C6.166,0.424 6.292,0.625 6.343,0.858L7.358,5.814L7.526,6.913L7.575,6.913L7.729,5.814L8.653,0.781C8.695,0.571 8.805,0.391 8.982,0.242C9.16,0.093 9.356,0.018 9.57,0.018C9.874,0.018 10.114,0.128 10.291,0.347C10.473,0.566 10.529,0.828 10.459,1.131L8.765,9.342C8.709,9.594 8.574,9.811 8.359,9.993C8.145,10.17 7.902,10.259 7.631,10.259C7.37,10.259 7.132,10.17 6.917,9.993C6.703,9.811 6.57,9.594 6.518,9.342L5.44,4.19L5.279,3.133L5.23,3.133L5.069,4.183L3.977,9.342C3.926,9.589 3.793,9.804 3.578,9.986C3.364,10.168 3.126,10.259 2.864,10.259Z" /> + + <path + android:fillColor="#000" + android:pathData="M13.676,4.396C13.497,4.396 13.342,4.332 13.212,4.204C13.084,4.073 13.02,3.917 13.02,3.736L13.02,0.792C13.02,0.611 13.084,0.456 13.212,0.328C13.342,0.197 13.497,0.132 13.676,0.132C13.854,0.132 14.008,0.197 14.136,0.328C14.264,0.456 14.328,0.611 14.328,0.792L14.328,3.736C14.328,3.917 14.264,4.073 14.136,4.204C14.008,4.332 13.854,4.396 13.676,4.396ZM12.252,2.908C12.073,2.908 11.92,2.845 11.792,2.72C11.664,2.592 11.6,2.44 11.6,2.264C11.6,2.088 11.664,1.937 11.792,1.812C11.92,1.684 12.073,1.62 12.252,1.62L15.1,1.62C15.278,1.62 15.432,1.684 15.56,1.812C15.688,1.937 15.752,2.088 15.752,2.264C15.752,2.44 15.688,2.592 15.56,2.72C15.432,2.845 15.278,2.908 15.1,2.908L12.252,2.908Z" /> + +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml new file mode 100644 index 000000000000..febcd87efbc3 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_e_mobiledata_updated.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="31.08dp" + android:viewportWidth="5.48" + android:viewportHeight="10.02"> + <path + android:pathData="M1.081,10.02C0.787,10.02 0.533,9.913 0.318,9.698C0.104,9.483 -0.004,9.229 -0.004,8.935L-0.004,1.081C-0.004,0.787 0.104,0.533 0.318,0.318C0.533,0.103 0.787,-0.004 1.081,-0.004L4.455,-0.004C4.707,-0.004 4.922,0.087 5.099,0.269C5.281,0.446 5.372,0.659 5.372,0.906C5.372,1.153 5.281,1.368 5.099,1.55C4.922,1.727 4.707,1.816 4.455,1.816L1.963,1.816L1.963,8.2L4.56,8.2C4.812,8.2 5.027,8.291 5.204,8.473C5.386,8.65 5.477,8.863 5.477,9.11C5.477,9.357 5.386,9.572 5.204,9.754C5.027,9.931 4.812,10.02 4.56,10.02L1.081,10.02ZM1.186,5.736L1.186,4.042L3.951,4.042C4.185,4.042 4.385,4.126 4.553,4.294C4.721,4.457 4.805,4.656 4.805,4.889C4.805,5.118 4.721,5.316 4.553,5.484C4.385,5.652 4.185,5.736 3.951,5.736L1.186,5.736Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml new file mode 100644 index 000000000000..d719f7a05aa0 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_g_mobiledata_updated.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="24.37dp" + android:viewportWidth="7.27" + android:viewportHeight="10.42"> + <path + android:pathData="M3.696,10.416C2.571,10.411 1.673,10.031 1.001,9.275C0.333,8.514 -0,7.406 -0,5.95L-0,4.417C-0,2.975 0.34,1.878 1.022,1.127C1.703,0.371 2.615,-0.005 3.759,0C4.272,0 4.706,0.075 5.061,0.224C5.42,0.369 5.726,0.576 5.978,0.847C6.235,1.113 6.412,1.374 6.51,1.631C6.608,1.883 6.615,2.121 6.531,2.345C6.447,2.569 6.302,2.732 6.097,2.835C5.896,2.938 5.7,2.968 5.509,2.926C5.317,2.884 5.168,2.802 5.061,2.681C4.953,2.555 4.844,2.422 4.732,2.282C4.62,2.142 4.48,2.032 4.312,1.953C4.144,1.869 3.943,1.827 3.71,1.827C3.192,1.822 2.776,2.011 2.464,2.394C2.156,2.777 2.002,3.358 2.002,4.137L2.002,6.293C2.002,7.063 2.16,7.644 2.478,8.036C2.8,8.428 3.22,8.624 3.738,8.624C4.242,8.624 4.636,8.477 4.921,8.183C5.205,7.889 5.359,7.474 5.383,6.937L5.383,6.265L4.41,6.265C4.204,6.265 4.027,6.188 3.878,6.034C3.728,5.875 3.654,5.689 3.654,5.474C3.654,5.255 3.731,5.068 3.885,4.914C4.043,4.755 4.232,4.676 4.452,4.676L6.419,4.676C6.652,4.676 6.85,4.755 7.014,4.914C7.177,5.073 7.261,5.269 7.266,5.502L7.266,6.538C7.266,7.77 6.944,8.724 6.3,9.401C5.661,10.078 4.792,10.416 3.696,10.416Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml new file mode 100644 index 000000000000..e60ff8cde396 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_h_mobiledata_updated.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="26.68dp" + android:viewportWidth="6.53" + android:viewportHeight="10.25"> + <path + android:pathData="M5.547,10.252C5.277,10.252 5.043,10.154 4.847,9.958C4.656,9.757 4.56,9.522 4.56,9.251L4.56,1.005C4.56,0.73 4.656,0.494 4.847,0.298C5.043,0.102 5.277,0.004 5.547,0.004C5.818,0.004 6.049,0.102 6.24,0.298C6.436,0.494 6.534,0.73 6.534,1.005L6.534,9.251C6.534,9.522 6.436,9.757 6.24,9.958C6.049,10.154 5.818,10.252 5.547,10.252ZM0.99,10.252C0.72,10.252 0.486,10.154 0.29,9.958C0.099,9.757 0.003,9.522 0.003,9.251L0.003,1.005C0.003,0.73 0.099,0.494 0.29,0.298C0.486,0.102 0.72,0.004 0.99,0.004C1.261,0.004 1.492,0.102 1.683,0.298C1.879,0.494 1.977,0.73 1.977,1.005L1.977,9.251C1.977,9.522 1.879,9.757 1.683,9.958C1.492,10.154 1.261,10.252 0.99,10.252ZM1.151,5.933L1.151,4.106L5.484,4.106L5.484,5.933L1.151,5.933Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml new file mode 100644 index 000000000000..e02df563dfdd --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_h_plus_mobiledata_updated.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="13.52dp" + android:viewportWidth="12.13" + android:viewportHeight="10.25"> + <path + android:pathData="M5.541,10.252C5.271,10.252 5.037,10.154 4.841,9.958C4.65,9.757 4.554,9.522 4.554,9.251L4.554,1.005C4.554,0.73 4.65,0.494 4.841,0.298C5.037,0.102 5.271,0.004 5.541,0.004C5.812,0.004 6.043,0.102 6.234,0.298C6.43,0.494 6.528,0.73 6.528,1.005L6.528,9.251C6.528,9.522 6.43,9.757 6.234,9.958C6.043,10.154 5.812,10.252 5.541,10.252ZM0.984,10.252C0.714,10.252 0.48,10.154 0.284,9.958C0.093,9.757 -0.003,9.522 -0.003,9.251L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,9.251C1.971,9.522 1.873,9.757 1.677,9.958C1.486,10.154 1.255,10.252 0.984,10.252ZM1.145,5.933L1.145,4.106L5.478,4.106L5.478,5.933L1.145,5.933Z" + android:fillColor="#000"/> + <path + android:pathData="M10.056,4.396C9.877,4.396 9.722,4.332 9.592,4.204C9.464,4.073 9.4,3.917 9.4,3.736L9.4,0.792C9.4,0.611 9.464,0.456 9.592,0.328C9.722,0.197 9.877,0.132 10.056,0.132C10.234,0.132 10.388,0.197 10.516,0.328C10.644,0.456 10.708,0.611 10.708,0.792L10.708,3.736C10.708,3.917 10.644,4.073 10.516,4.204C10.388,4.332 10.234,4.396 10.056,4.396ZM8.632,2.908C8.453,2.908 8.3,2.845 8.172,2.72C8.044,2.592 7.98,2.44 7.98,2.264C7.98,2.088 8.044,1.937 8.172,1.812C8.3,1.684 8.453,1.62 8.632,1.62L11.48,1.62C11.658,1.62 11.812,1.684 11.94,1.812C12.068,1.937 12.132,2.088 12.132,2.264C12.132,2.44 12.068,2.592 11.94,2.72C11.812,2.845 11.658,2.908 11.48,2.908L8.632,2.908Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml new file mode 100644 index 000000000000..9d64439cf30b --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_lte_mobiledata_updated.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="20dp" + android:height="11.92dp" + android:viewportWidth="17.2" + android:viewportHeight="10.25"> + <path + android:pathData="M1.082,10.14C0.788,10.14 0.534,10.033 0.319,9.818C0.105,9.603 -0.003,9.349 -0.003,9.055L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,8.313L4.19,8.313C4.442,8.313 4.659,8.404 4.841,8.586C5.023,8.763 5.114,8.976 5.114,9.223C5.114,9.475 5.023,9.692 4.841,9.874C4.659,10.051 4.442,10.14 4.19,10.14L1.082,10.14ZM7.59,10.252C7.32,10.252 7.086,10.154 6.89,9.958C6.694,9.757 6.596,9.522 6.596,9.251L6.596,1.068L8.577,1.068L8.577,9.251C8.577,9.522 8.479,9.757 8.283,9.958C8.087,10.154 7.856,10.252 7.59,10.252ZM5.413,1.936C5.161,1.936 4.944,1.847 4.762,1.67C4.585,1.488 4.496,1.273 4.496,1.026C4.496,0.779 4.585,0.566 4.762,0.389C4.944,0.207 5.161,0.116 5.413,0.116L9.753,0.116C10.005,0.116 10.222,0.207 10.404,0.389C10.586,0.566 10.677,0.779 10.677,1.026C10.677,1.273 10.586,1.488 10.404,1.67C10.222,1.847 10.005,1.936 9.753,1.936L5.413,1.936ZM12.799,10.14C12.505,10.14 12.251,10.033 12.036,9.818C11.821,9.603 11.714,9.349 11.714,9.055L11.714,1.201C11.714,0.907 11.821,0.653 12.036,0.438C12.251,0.223 12.505,0.116 12.799,0.116L16.173,0.116C16.425,0.116 16.64,0.207 16.817,0.389C16.999,0.566 17.09,0.779 17.09,1.026C17.09,1.273 16.999,1.488 16.817,1.67C16.64,1.847 16.425,1.936 16.173,1.936L13.681,1.936L13.681,8.32L16.278,8.32C16.53,8.32 16.745,8.411 16.922,8.593C17.104,8.77 17.195,8.983 17.195,9.23C17.195,9.477 17.104,9.692 16.922,9.874C16.745,10.051 16.53,10.14 16.278,10.14L12.799,10.14ZM12.904,5.856L12.904,4.162L15.669,4.162C15.902,4.162 16.103,4.246 16.271,4.414C16.439,4.577 16.523,4.776 16.523,5.009C16.523,5.238 16.439,5.436 16.271,5.604C16.103,5.772 15.902,5.856 15.669,5.856L12.904,5.856Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml b/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml new file mode 100644 index 000000000000..7075516e6dd3 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_lte_plus_mobiledata_updated.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="25dp" + android:height="11.85dp" + android:viewportWidth="21.63" + android:viewportHeight="10.25"> + <path + android:pathData="M1.082,10.14C0.788,10.14 0.534,10.033 0.319,9.818C0.105,9.603 -0.003,9.349 -0.003,9.055L-0.003,1.005C-0.003,0.73 0.093,0.494 0.284,0.298C0.48,0.102 0.714,0.004 0.984,0.004C1.255,0.004 1.486,0.102 1.677,0.298C1.873,0.494 1.971,0.73 1.971,1.005L1.971,8.313L4.19,8.313C4.442,8.313 4.659,8.404 4.841,8.586C5.023,8.763 5.114,8.976 5.114,9.223C5.114,9.475 5.023,9.692 4.841,9.874C4.659,10.051 4.442,10.14 4.19,10.14L1.082,10.14ZM7.59,10.252C7.32,10.252 7.086,10.154 6.89,9.958C6.694,9.757 6.596,9.522 6.596,9.251L6.596,1.068L8.577,1.068L8.577,9.251C8.577,9.522 8.479,9.757 8.283,9.958C8.087,10.154 7.856,10.252 7.59,10.252ZM5.413,1.936C5.161,1.936 4.944,1.847 4.762,1.67C4.585,1.488 4.496,1.273 4.496,1.026C4.496,0.779 4.585,0.566 4.762,0.389C4.944,0.207 5.161,0.116 5.413,0.116L9.753,0.116C10.005,0.116 10.222,0.207 10.404,0.389C10.586,0.566 10.677,0.779 10.677,1.026C10.677,1.273 10.586,1.488 10.404,1.67C10.222,1.847 10.005,1.936 9.753,1.936L5.413,1.936ZM12.799,10.14C12.505,10.14 12.251,10.033 12.036,9.818C11.821,9.603 11.714,9.349 11.714,9.055L11.714,1.201C11.714,0.907 11.821,0.653 12.036,0.438C12.251,0.223 12.505,0.116 12.799,0.116L16.173,0.116C16.425,0.116 16.64,0.207 16.817,0.389C16.999,0.566 17.09,0.779 17.09,1.026C17.09,1.273 16.999,1.488 16.817,1.67C16.64,1.847 16.425,1.936 16.173,1.936L13.681,1.936L13.681,8.32L16.278,8.32C16.53,8.32 16.745,8.411 16.922,8.593C17.104,8.77 17.195,8.983 17.195,9.23C17.195,9.477 17.104,9.692 16.922,9.874C16.745,10.051 16.53,10.14 16.278,10.14L12.799,10.14ZM12.904,5.856L12.904,4.162L15.669,4.162C15.902,4.162 16.103,4.246 16.271,4.414C16.439,4.577 16.523,4.776 16.523,5.009C16.523,5.238 16.439,5.436 16.271,5.604C16.103,5.772 15.902,5.856 15.669,5.856L12.904,5.856Z" + android:fillColor="#000"/> + <path + android:pathData="M19.556,4.396C19.377,4.396 19.222,4.332 19.092,4.204C18.964,4.073 18.9,3.917 18.9,3.736L18.9,0.792C18.9,0.611 18.964,0.456 19.092,0.328C19.222,0.197 19.377,0.132 19.556,0.132C19.734,0.132 19.888,0.197 20.016,0.328C20.144,0.456 20.208,0.611 20.208,0.792L20.208,3.736C20.208,3.917 20.144,4.073 20.016,4.204C19.888,4.332 19.734,4.396 19.556,4.396ZM18.132,2.908C17.953,2.908 17.8,2.845 17.672,2.72C17.544,2.592 17.48,2.44 17.48,2.264C17.48,2.088 17.544,1.937 17.672,1.812C17.8,1.684 17.953,1.62 18.132,1.62L20.98,1.62C21.158,1.62 21.312,1.684 21.44,1.812C21.568,1.937 21.632,2.088 21.632,2.264C21.632,2.44 21.568,2.592 21.44,2.72C21.312,2.845 21.158,2.908 20.98,2.908L18.132,2.908Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml index 6015be8c894f..aa5e9d28cabe 100644 --- a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml +++ b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml @@ -23,10 +23,10 @@ <clip-path android:pathData=" M0,0 - V13.5,0 - H13.5,20 - V0,20 - H0,0 + H16 + V12 + H0 + Z M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" /> <path android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml index fb73b6b253e1..f7bf8518a55c 100644 --- a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml +++ b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml @@ -8,10 +8,10 @@ <clip-path android:pathData=" M0,0 - V13.5,0 - H13.5,20 - V0,20 - H0,0 + H16 + V12 + H0 + Z M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" /> <path android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml index 7c4c1c6b1126..016c614846e9 100644 --- a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml +++ b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml @@ -23,10 +23,10 @@ <clip-path android:pathData=" M0,0 - V13.5,0 - H13.5,20 - V0,20 - H0,0 + H16 + V12 + H0 + Z M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" /> <path android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml index d23680d17b9c..b8304151eefe 100644 --- a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml +++ b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml @@ -23,10 +23,10 @@ <clip-path android:pathData=" M0,0 - V13.5,0 - H13.5,20 - V0,20 - H0,0 + H16 + V12 + H0 + Z M14.999,13.5C17.761,13.5 19.999,11.261 19.999,8.5C19.999,5.739 17.761,3.5 14.999,3.5C12.238,3.5 9.999,5.739 9.999,8.5C9.999,11.261 12.238,13.5 14.999,13.5Z" /> <path android:pathData="M1.249,7C1.939,7 2.499,7.56 2.499,8.25L2.499,10.75C2.499,11.44 1.939,12 1.249,12C0.559,12 -0.001,11.44 -0.001,10.75L-0.001,8.25C-0.001,7.56 0.559,7 1.249,7Z" diff --git a/packages/SettingsLib/res/drawable/ic_wifi_0.xml b/packages/SettingsLib/res/drawable/ic_wifi_0.xml index 8ff65540c505..7f98457a4c76 100644 --- a/packages/SettingsLib/res/drawable/ic_wifi_0.xml +++ b/packages/SettingsLib/res/drawable/ic_wifi_0.xml @@ -1,5 +1,5 @@ <!-- - Copyright (C) 2023 The Android Open Source Project + Copyright (C) 2025 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,24 +14,24 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="18dp" - android:height="13dp" - android:viewportWidth="18.0" - android:viewportHeight="13.0"> - <path - android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:width="17.0dp" + android:height="12.58dp" + android:viewportHeight="12.0" + android:viewportWidth="16.21"> + <path - android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M12.659,7.45C13.199,6.91 13.149,6.01 12.479,5.64C11.179,4.92 9.689,4.51 8.109,4.51C6.529,4.51 5.029,4.92 3.739,5.64C3.069,6.01 3.019,6.91 3.559,7.45C3.999,7.89 4.699,7.94 5.259,7.66C6.119,7.24 7.089,7 8.109,7C9.129,7 10.099,7.24 10.959,7.66C11.519,7.94 12.219,7.89 12.659,7.45Z" /> + <path - android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M15.85,4.26C16.36,3.75 16.34,2.91 15.76,2.49C13.61,0.93 10.97,0 8.11,0C5.25,0 2.61,0.92 0.46,2.49C-0.12,2.91 -0.14,3.75 0.37,4.26C0.84,4.73 1.59,4.75 2.13,4.37C3.83,3.19 5.89,2.5 8.11,2.5C10.33,2.5 12.39,3.19 14.09,4.37C14.63,4.75 15.38,4.73 15.85,4.26Z" /> + <path - android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M8.109,12C8.938,12 9.609,11.328 9.609,10.5C9.609,9.672 8.938,9 8.109,9C7.281,9 6.609,9.672 6.609,10.5C6.609,11.328 7.281,12 8.109,12Z" /> + </vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml index db31b9dd0fcd..3a9bba5cd526 100644 --- a/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml +++ b/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml @@ -1,28 +1,52 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17dp" - android:height="13dp" - android:viewportWidth="17.0" - android:viewportHeight="13.0"> + android:width="21.0dp" + android:height="15.66dp" + android:viewportHeight="13.5" + android:viewportWidth="18.1"> + + <group> + <!-- clip-out the circle which will contain the exclamation point (below this group) --> + <clip-path android:pathData=" + M0,0 + H18.1 + V13.5 + H0 + Z + M15.109,13.5C17.871,13.5 20.109,11.261 20.109,8.5C20.109,5.739 17.871,3.5 15.109,3.5C12.348,3.5 10.109,5.739 10.109,8.5C10.109,11.261 12.348,13.5 15.109,13.5Z" /> + + <path + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M8.109,12C8.938,12 9.609,11.328 9.609,10.5C9.609,9.672 8.938,9 8.109,9C7.281,9 6.609,9.672 6.609,10.5C6.609,11.328 7.281,12 8.109,12Z" /> + + <path + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M12.659,7.45C13.199,6.91 13.149,6.01 12.479,5.64C11.179,4.92 9.689,4.51 8.109,4.51C6.529,4.51 5.029,4.92 3.739,5.64C3.069,6.01 3.019,6.91 3.559,7.45C3.999,7.89 4.699,7.94 5.259,7.66C6.119,7.24 7.089,7 8.109,7C9.129,7 10.099,7.24 10.959,7.66C11.519,7.94 12.219,7.89 12.659,7.45Z" /> + + <path + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M15.85,4.26C16.36,3.75 16.34,2.91 15.76,2.49C13.61,0.93 10.97,0 8.11,0C5.25,0 2.61,0.92 0.46,2.49C-0.12,2.91 -0.14,3.75 0.37,4.26C0.84,4.73 1.59,4.75 2.13,4.37C3.83,3.19 5.89,2.5 8.11,2.5C10.33,2.5 12.39,3.19 14.09,4.37C14.63,4.75 15.38,4.73 15.85,4.26Z" /> + </group> + <path - android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M15.109,5C14.699,5 14.359,5.34 14.359,5.75L14.359,8.75C14.359,9.16 14.699,9.5 15.109,9.5C15.519,9.5 15.859,9.16 15.859,8.75L15.859,5.75C15.859,5.34 15.519,5 15.109,5ZM15.109,12C15.519,12 15.859,11.66 15.859,11.25C15.859,10.84 15.519,10.5 15.109,10.5C14.699,10.5 14.359,10.84 14.359,11.25C14.359,11.66 14.699,12 15.109,12Z" /> + </vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_1.xml b/packages/SettingsLib/res/drawable/ic_wifi_1.xml index e170f1dadc94..9c661f4b5d7a 100644 --- a/packages/SettingsLib/res/drawable/ic_wifi_1.xml +++ b/packages/SettingsLib/res/drawable/ic_wifi_1.xml @@ -1,5 +1,5 @@ <!-- - Copyright (C) 2023 The Android Open Source Project + Copyright (C) 2025 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,23 +14,23 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="18dp" - android:height="13dp" - android:viewportWidth="18.0" - android:viewportHeight="13.0"> - <path - android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:width="17.0dp" + android:height="12.58dp" + android:viewportHeight="12.0" + android:viewportWidth="16.21"> + <path - android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M12.659,7.45C13.199,6.91 13.149,6.01 12.479,5.64C11.179,4.92 9.689,4.51 8.109,4.51C6.529,4.51 5.029,4.92 3.739,5.64C3.069,6.01 3.019,6.91 3.559,7.45C3.999,7.89 4.699,7.94 5.259,7.66C6.119,7.24 7.089,7 8.109,7C9.129,7 10.099,7.24 10.959,7.66C11.519,7.94 12.219,7.89 12.659,7.45Z" /> + <path - android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M15.85,4.26C16.36,3.75 16.34,2.91 15.76,2.49C13.61,0.93 10.97,0 8.11,0C5.25,0 2.61,0.92 0.46,2.49C-0.12,2.91 -0.14,3.75 0.37,4.26C0.84,4.73 1.59,4.75 2.13,4.37C3.83,3.19 5.89,2.5 8.11,2.5C10.33,2.5 12.39,3.19 14.09,4.37C14.63,4.75 15.38,4.73 15.85,4.26Z" /> + <path - android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M8.109,12C8.938,12 9.609,11.328 9.609,10.5C9.609,9.672 8.938,9 8.109,9C7.281,9 6.609,9.672 6.609,10.5C6.609,11.328 7.281,12 8.109,12Z" /> + </vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml index a4d6a5c00b15..32a69f5e810c 100644 --- a/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml +++ b/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml @@ -1,27 +1,51 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17dp" - android:height="13dp" - android:viewportWidth="17.0" - android:viewportHeight="13.0"> + android:width="21.0dp" + android:height="15.66dp" + android:viewportHeight="13.5" + android:viewportWidth="18.1"> + + <group> + <!-- clip-out the circle which will contain the exclamation point (below this group) --> + <clip-path android:pathData=" + M0,0 + H18.1 + V13.5 + H0 + Z + M15.109,13.5C17.871,13.5 20.109,11.261 20.109,8.5C20.109,5.739 17.871,3.5 15.109,3.5C12.348,3.5 10.109,5.739 10.109,8.5C10.109,11.261 12.348,13.5 15.109,13.5Z" /> + + <path + android:fillColor="#000" + android:pathData="M8.109,12C8.938,12 9.609,11.328 9.609,10.5C9.609,9.672 8.938,9 8.109,9C7.281,9 6.609,9.672 6.609,10.5C6.609,11.328 7.281,12 8.109,12Z" /> + + <path + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M12.659,7.45C13.199,6.91 13.149,6.01 12.479,5.64C11.179,4.92 9.689,4.51 8.109,4.51C6.529,4.51 5.029,4.92 3.739,5.64C3.069,6.01 3.019,6.91 3.559,7.45C3.999,7.89 4.699,7.94 5.259,7.66C6.119,7.24 7.089,7 8.109,7C9.129,7 10.099,7.24 10.959,7.66C11.519,7.94 12.219,7.89 12.659,7.45Z" /> + + <path + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M15.85,4.26C16.36,3.75 16.34,2.91 15.76,2.49C13.61,0.93 10.97,0 8.11,0C5.25,0 2.61,0.92 0.46,2.49C-0.12,2.91 -0.14,3.75 0.37,4.26C0.84,4.73 1.59,4.75 2.13,4.37C3.83,3.19 5.89,2.5 8.11,2.5C10.33,2.5 12.39,3.19 14.09,4.37C14.63,4.75 15.38,4.73 15.85,4.26Z" /> + </group> + <path - android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M15.109,5C14.699,5 14.359,5.34 14.359,5.75L14.359,8.75C14.359,9.16 14.699,9.5 15.109,9.5C15.519,9.5 15.859,9.16 15.859,8.75L15.859,5.75C15.859,5.34 15.519,5 15.109,5ZM15.109,12C15.519,12 15.859,11.66 15.859,11.25C15.859,10.84 15.519,10.5 15.109,10.5C14.699,10.5 14.359,10.84 14.359,11.25C14.359,11.66 14.699,12 15.109,12Z" /> + </vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_2.xml b/packages/SettingsLib/res/drawable/ic_wifi_2.xml index fc62267ad5b0..02c14e18a95a 100644 --- a/packages/SettingsLib/res/drawable/ic_wifi_2.xml +++ b/packages/SettingsLib/res/drawable/ic_wifi_2.xml @@ -1,5 +1,5 @@ <!-- - Copyright (C) 2023 The Android Open Source Project + Copyright (C) 2025 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,22 +14,22 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="18dp" - android:height="13dp" - android:viewportWidth="18.0" - android:viewportHeight="13.0"> - <path - android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:width="17.0dp" + android:height="12.58dp" + android:viewportHeight="12.0" + android:viewportWidth="16.21"> + <path - android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M12.659,7.45C13.199,6.91 13.149,6.01 12.479,5.64C11.179,4.92 9.689,4.51 8.109,4.51C6.529,4.51 5.029,4.92 3.739,5.64C3.069,6.01 3.019,6.91 3.559,7.45C3.999,7.89 4.699,7.94 5.259,7.66C6.119,7.24 7.089,7 8.109,7C9.129,7 10.099,7.24 10.959,7.66C11.519,7.94 12.219,7.89 12.659,7.45Z" /> + <path - android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" - android:fillColor="#000"/> + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M15.85,4.26C16.36,3.75 16.34,2.91 15.76,2.49C13.61,0.93 10.97,0 8.11,0C5.25,0 2.61,0.92 0.46,2.49C-0.12,2.91 -0.14,3.75 0.37,4.26C0.84,4.73 1.59,4.75 2.13,4.37C3.83,3.19 5.89,2.5 8.11,2.5C10.33,2.5 12.39,3.19 14.09,4.37C14.63,4.75 15.38,4.73 15.85,4.26Z" /> + <path - android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M8.109,12C8.938,12 9.609,11.328 9.609,10.5C9.609,9.672 8.938,9 8.109,9C7.281,9 6.609,9.672 6.609,10.5C6.609,11.328 7.281,12 8.109,12Z" /> + </vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml index 65f40eff1ca8..da0aa12de564 100644 --- a/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml +++ b/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml @@ -1,26 +1,50 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17dp" - android:height="13dp" - android:viewportWidth="17.0" - android:viewportHeight="13.0"> + android:width="21.0dp" + android:height="15.66dp" + android:viewportHeight="13.5" + android:viewportWidth="18.1"> + + <group> + <!-- clip-out the circle which will contain the exclamation point (below this group) --> + <clip-path android:pathData=" + M0,0 + H18.1 + V13.5 + H0 + Z + M15.109,13.5C17.871,13.5 20.109,11.261 20.109,8.5C20.109,5.739 17.871,3.5 15.109,3.5C12.348,3.5 10.109,5.739 10.109,8.5C10.109,11.261 12.348,13.5 15.109,13.5Z" /> + + <path + android:fillColor="#000" + android:pathData="M8.109,12C8.938,12 9.609,11.328 9.609,10.5C9.609,9.672 8.938,9 8.109,9C7.281,9 6.609,9.672 6.609,10.5C6.609,11.328 7.281,12 8.109,12Z" /> + + <path + android:fillColor="#000" + android:pathData="M12.659,7.45C13.199,6.91 13.149,6.01 12.479,5.64C11.179,4.92 9.689,4.51 8.109,4.51C6.529,4.51 5.029,4.92 3.739,5.64C3.069,6.01 3.019,6.91 3.559,7.45C3.999,7.89 4.699,7.94 5.259,7.66C6.119,7.24 7.089,7 8.109,7C9.129,7 10.099,7.24 10.959,7.66C11.519,7.94 12.219,7.89 12.659,7.45Z" /> + + <path + android:fillAlpha="0.45" + android:fillColor="#000" + android:pathData="M15.85,4.26C16.36,3.75 16.34,2.91 15.76,2.49C13.61,0.93 10.97,0 8.11,0C5.25,0 2.61,0.92 0.46,2.49C-0.12,2.91 -0.14,3.75 0.37,4.26C0.84,4.73 1.59,4.75 2.13,4.37C3.83,3.19 5.89,2.5 8.11,2.5C10.33,2.5 12.39,3.19 14.09,4.37C14.63,4.75 15.38,4.73 15.85,4.26Z" /> + </group> + <path - android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" - android:fillColor="#000"/> - <path - android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M15.109,5C14.699,5 14.359,5.34 14.359,5.75L14.359,8.75C14.359,9.16 14.699,9.5 15.109,9.5C15.519,9.5 15.859,9.16 15.859,8.75L15.859,5.75C15.859,5.34 15.519,5 15.109,5ZM15.109,12C15.519,12 15.859,11.66 15.859,11.25C15.859,10.84 15.519,10.5 15.109,10.5C14.699,10.5 14.359,10.84 14.359,11.25C14.359,11.66 14.699,12 15.109,12Z" /> + </vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_3.xml b/packages/SettingsLib/res/drawable/ic_wifi_3.xml index 9079daf922b8..6b183aff40f0 100644 --- a/packages/SettingsLib/res/drawable/ic_wifi_3.xml +++ b/packages/SettingsLib/res/drawable/ic_wifi_3.xml @@ -1,5 +1,5 @@ <!-- - Copyright (C) 2023 The Android Open Source Project + Copyright (C) 2025 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,21 +14,21 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="18dp" - android:height="13dp" - android:viewportWidth="18.0" - android:viewportHeight="13.0"> - <path - android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" - android:fillAlpha="0.24" - android:fillColor="#000"/> + android:width="17.0dp" + android:height="12.58dp" + android:viewportHeight="12.0" + android:viewportWidth="16.21"> + <path - android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M12.659,7.45C13.199,6.91 13.149,6.01 12.479,5.64C11.179,4.92 9.689,4.51 8.109,4.51C6.529,4.51 5.029,4.92 3.739,5.64C3.069,6.01 3.019,6.91 3.559,7.45C3.999,7.89 4.699,7.94 5.259,7.66C6.119,7.24 7.089,7 8.109,7C9.129,7 10.099,7.24 10.959,7.66C11.519,7.94 12.219,7.89 12.659,7.45Z" /> + <path - android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M15.85,4.26C16.36,3.75 16.34,2.91 15.76,2.49C13.61,0.93 10.97,0 8.11,0C5.25,0 2.61,0.92 0.46,2.49C-0.12,2.91 -0.14,3.75 0.37,4.26C0.84,4.73 1.59,4.75 2.13,4.37C3.83,3.19 5.89,2.5 8.11,2.5C10.33,2.5 12.39,3.19 14.09,4.37C14.63,4.75 15.38,4.73 15.85,4.26Z" /> + <path - android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M8.109,12C8.938,12 9.609,11.328 9.609,10.5C9.609,9.672 8.938,9 8.109,9C7.281,9 6.609,9.672 6.609,10.5C6.609,11.328 7.281,12 8.109,12Z" /> + </vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml index 940781bbb1ca..c30affad6a80 100644 --- a/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml +++ b/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml @@ -1,25 +1,49 @@ +<!-- + Copyright (C) 2025 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17dp" - android:height="13dp" - android:viewportWidth="17.0" - android:viewportHeight="13.0"> + android:width="21.0dp" + android:height="15.66dp" + android:viewportHeight="13.5" + android:viewportWidth="18.1"> + + <group> + <!-- clip-out the circle which will contain the exclamation point (below this group) --> + <clip-path android:pathData=" + M0,0 + H18.1 + V13.5 + H0 + Z + M15.109,13.5C17.871,13.5 20.109,11.261 20.109,8.5C20.109,5.739 17.871,3.5 15.109,3.5C12.348,3.5 10.109,5.739 10.109,8.5C10.109,11.261 12.348,13.5 15.109,13.5Z" /> + + <path + android:fillColor="#000" + android:pathData="M8.109,12C8.938,12 9.609,11.328 9.609,10.5C9.609,9.672 8.938,9 8.109,9C7.281,9 6.609,9.672 6.609,10.5C6.609,11.328 7.281,12 8.109,12Z" /> + + <path + android:fillColor="#000" + android:pathData="M12.659,7.45C13.199,6.91 13.149,6.01 12.479,5.64C11.179,4.92 9.689,4.51 8.109,4.51C6.529,4.51 5.029,4.92 3.739,5.64C3.069,6.01 3.019,6.91 3.559,7.45C3.999,7.89 4.699,7.94 5.259,7.66C6.119,7.24 7.089,7 8.109,7C9.129,7 10.099,7.24 10.959,7.66C11.519,7.94 12.219,7.89 12.659,7.45Z" /> + + <path + android:fillColor="#000" + android:pathData="M15.85,4.26C16.36,3.75 16.34,2.91 15.76,2.49C13.61,0.93 10.97,0 8.11,0C5.25,0 2.61,0.92 0.46,2.49C-0.12,2.91 -0.14,3.75 0.37,4.26C0.84,4.73 1.59,4.75 2.13,4.37C3.83,3.19 5.89,2.5 8.11,2.5C10.33,2.5 12.39,3.19 14.09,4.37C14.63,4.75 15.38,4.73 15.85,4.26Z" /> + </group> + <path - android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" - android:fillAlpha="0.3" - android:fillColor="#000"/> - <path - android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" - android:fillColor="#000"/> - <path - android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" - android:fillColor="#000"/> - <path - android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" - android:fillColor="#000"/> + android:fillColor="#000" + android:pathData="M15.109,5C14.699,5 14.359,5.34 14.359,5.75L14.359,8.75C14.359,9.16 14.699,9.5 15.109,9.5C15.519,9.5 15.859,9.16 15.859,8.75L15.859,5.75C15.859,5.34 15.519,5 15.109,5ZM15.109,12C15.519,12 15.859,11.66 15.859,11.25C15.859,10.84 15.519,10.5 15.109,10.5C14.699,10.5 14.359,10.84 14.359,11.25C14.359,11.66 14.699,12 15.109,12Z" /> + </vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_4.xml b/packages/SettingsLib/res/drawable/ic_wifi_4.xml deleted file mode 100644 index 6185e4a83332..000000000000 --- a/packages/SettingsLib/res/drawable/ic_wifi_4.xml +++ /dev/null @@ -1,33 +0,0 @@ -<!-- - Copyright (C) 2023 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="18dp" - android:height="13dp" - android:viewportWidth="18.0" - android:viewportHeight="13.0"> - <path - android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" - android:fillColor="#000"/> - <path - android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" - android:fillColor="#000"/> - <path - android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" - android:fillColor="#000"/> - <path - android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" - android:fillColor="#000"/> -</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml deleted file mode 100644 index 715aaa0982e9..000000000000 --- a/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml +++ /dev/null @@ -1,24 +0,0 @@ -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="17dp" - android:height="13dp" - android:viewportWidth="17.0" - android:viewportHeight="13.0"> - <path - android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" - android:fillColor="#000"/> - <path - android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" - android:fillColor="#000"/> - <path - android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" - android:fillColor="#000"/> - <path - android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" - android:fillColor="#000"/> - <path - android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" - android:fillColor="#000"/> -</vector> diff --git a/packages/SystemUI/res/xml/volume_dialog_scene.xml b/packages/SettingsLib/res/layout/activity_create_new_user.xml index b813474490bb..7453b53a6956 100644 --- a/packages/SystemUI/res/xml/volume_dialog_scene.xml +++ b/packages/SettingsLib/res/layout/activity_create_new_user.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright (C) 2024 The Android Open Source Project + ~ Copyright (C) 2025 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. @@ -14,14 +14,9 @@ ~ limitations under the License. --> -<MotionScene xmlns:motion="http://schemas.android.com/apk/res-auto"> - - <Transition - motion:autoTransition="none" - motion:constraintSetEnd="@id/volume_dialog_half_folded_constraint_set" - motion:constraintSetStart="@id/volume_dialog_constraint_set" - motion:duration="150" /> - - <Include motion:constraintSet="@xml/volume_dialog_constraint_set" /> - <Include motion:constraintSet="@xml/volume_dialog_half_folded_constraint_set" /> -</MotionScene>
\ No newline at end of file +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/transparent" + android:orientation="vertical"> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml index c4ba7eb03ae8..89648d1e0f52 100644 --- a/packages/SettingsLib/res/values-af/arrays.xml +++ b/packages/SettingsLib/res/values-af/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Slegs toestelskerm (verstek)"</item> + <item msgid="9161645858025071955">"Eksterne skerm"</item> + <item msgid="23651860565814477">"Laaste interaksie met statusbalk"</item> + <item msgid="7521112827893653392">"Fokusgebaseer"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Wys skakering net op toestelskerm"</item> + <item msgid="1955398604822147783">"Wys skakering op enkele eksterne skerm"</item> + <item msgid="391477482416751568">"Wys skakering op die skerm waarop die statusbalk die laaste interaksie gehad het"</item> + <item msgid="1746820128097981528">"Wys skakering op die laaste gefokusde skerm"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 3a7e45209562..dbc4e5a2b1db 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Kon nie omgewing opdateer nie"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktief (net media). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiewe (net media). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Gekoppel (steun oudiodeling). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Gekoppel (steun oudiodeling). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Gekoppel (steun oudiodeling). Links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Gekoppel (steun oudiodeling). Regs: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Gekoppel (steun oudiodeling)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktief (net media)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Steun oudiodeling"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktief (net media), net linkerkant"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktief (net media), net regterkant"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktief (net media), linker- en regterkant"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardeware-versnelde lewering"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitering"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strengmodus geaktiveer"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Flits skerm as apps lang bewerkings uitvoer op die hoofdraad"</string> <string name="pointer_location" msgid="7516929526199520173">"Wyserligging"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Stel WebView-implementering"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Hierdie keuse is nie meer geldig nie. Probeer weer."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Fotokleurmodus"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Gebruik sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Gedeaktiveer"</string> diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml index a151f837a8a4..4ae2d99bf92a 100644 --- a/packages/SettingsLib/res/values-am/arrays.xml +++ b/packages/SettingsLib/res/values-am/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"የመሣሪያ ማሳያ ብቻ (ነባሪ)"</item> + <item msgid="9161645858025071955">"ውጫዊ ማሳያ"</item> + <item msgid="23651860565814477">"የቅርብ ጊዜ የሁኔታ አሞሌ ንክኪ"</item> + <item msgid="7521112827893653392">"ትኩረት ላይ የተመሠረተ"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"በመሣሪያ ማሳያ ላይ ብቻ ጥላ አሳይ"</item> + <item msgid="1955398604822147783">"በነጠላ ውጫዊ ማሳያ ላይ ጥላ አሳይ"</item> + <item msgid="391477482416751568">"ለመጨረሻ ጊዜ በሁኔታ አሞሌው መስተጋብር የተፈጠረበት ማሳያ ላይ ጥላ አሳይ"</item> + <item msgid="1746820128097981528">"ለመጨረሻ ጊዜ ትኩረት በተደረገበት ማሳያ ላይ ጥላ አሳይ"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 25e9c5e3b2a9..bfe60068ff6d 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"በዙሪያ ያሉትን ማዘመን አልተቻለም"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"ገቢር (ሚዲያ ብቻ)። <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ።"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"ገቢር (ሚዲያ ብቻ)። ግ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>፣ ቀ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ባትሪ።"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"ተገናኝቷል (የድምፅ ማጋራት ይደግፋል)፣ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ።"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"ተገናኝቷል (የድምፅ ማጋራት ይደግፋል) ግ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>፣ ቀ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ባትሪ።"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"ተገናኝቷል (የድምፅ ማጋራት ይደግፋል)። ግራ፦<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ።"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"ተገናኝቷል (የድምፅ ማጋራት ይደግፋል)። ቀኝ፦ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ባትሪ።"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"ተገናኝቷል (የድምፅ ማጋራት ይደግፋል)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ገቢር (ሚዲያ ብቻ)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ድምፅ ማጋራትን ይደግፋል"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ገቢር (ሚዲያ ብቻ)፣ ግራ ብቻ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ገቢር (ሚዲያ ብቻ) ቀኝ ብቻ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ገቢር (ሚዲያ ብቻ)፣ ግራ እና ቀኝ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"የተፋጠነ የሃርድዌር አሰጣጥ"</string> <string name="media_category" msgid="8122076702526144053">"ማህደረመረጃ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"ቁጥጥር"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"ጥብቅ ሁነታ ነቅቷል"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"መተግበሪያዎች ረጅም ክንውኖች ወደ ዋና ክሮች ሲያካሂዱ ማያላይ ብልጭ አድርግ።"</string> <string name="pointer_location" msgid="7516929526199520173">"የአመልካች ሥፍራ"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"የWebView ትግበራ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"የWebView ትግበራን ያዘጋጁ"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ይህ ምርጫ ከአሁን በኋላ የሚሰራ አይደለም። እንደገና ይሞክሩ።"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"የስዕል ቀለም ሁነታ"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ይጠቀሙ"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"ተሰናክሏል"</string> diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml index ebdb0c70cd3f..e3c36b875eef 100644 --- a/packages/SettingsLib/res/values-ar/arrays.xml +++ b/packages/SettingsLib/res/values-ar/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"شاشة الجهاز فقط (الإعداد التلقائي)"</item> + <item msgid="9161645858025071955">"الشاشة الخارجية"</item> + <item msgid="23651860565814477">"آخر لمسة على شريط الحالة"</item> + <item msgid="7521112827893653392">"على الشاشة التي يتم التركيز عليها"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"عرض الظل على شاشة الجهاز فقط"</item> + <item msgid="1955398604822147783">"عرض الظل على شاشة خارجية واحدة"</item> + <item msgid="391477482416751568">"عرض الظل على آخر شاشة تم التفاعل مع شريط الحالة فيها"</item> + <item msgid="1746820128097981528">"عرض الظل على آخر شاشة تم التركيز عليها"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 8956c44ec09e..64a021d1b8a7 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"تعذَّر تعديل حالة الأصوات المحيطة"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"البلوتوث نشِط (للوسائط فقط). مستوى شحن البطارية: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"البلوتوث نشِط (للوسائط فقط)، مستوى الشحن في سماعة الرأس اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، مستوى الشحن في سماعة الرأس اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة). مستوى شحن البطارية: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة). مستوى الشحن في سماعة الرأس اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، مستوى الشحن في سماعة الرأس اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة). مستوى الشحن في سماعة الرأس اليسرى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة). مستوى الشحن في سماعة الرأس اليمنى: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"البلوتوث متصل (ميزة \"مشاركة الصوت\" متاحة)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"البلوتوث مفعَّل (للوسائط فقط)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"تتوفّر ميزة \"مشاركة الصوت\""</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"السماعة اليسرى فقط مشغَّلة (للوسائط فقط)"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"السماعة اليمنى فقط مشغَّلة (للوسائط فقط)"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"السماعتان اليسرى واليمنى مشغَّلتان (للوسائط فقط)"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"عرض تسارع الأجهزة"</string> <string name="media_category" msgid="8122076702526144053">"الوسائط"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"المراقبة"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"تفعيل الوضع المتشدد"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"وميض الشاشة عند إجراء التطبيقات عمليات طويلة في سلسلة المحادثات الرئيسية"</string> <string name="pointer_location" msgid="7516929526199520173">"موقع المؤشر"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"تطبيق WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"تعيين تطبيق WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"لم يعد هذا الاختيار صالحًا. أعد المحاولة."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"نمط لون الصورة"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"استخدام sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"غير مفعّل"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index bfacbb248c0e..82ee7f3ab289 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"আশ-পাশ আপডে’ট কৰিব পৰা নগ’ল"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া)। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী।"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া)। বাওঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, সোঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰী।"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী।"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে), বাওঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, সোঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> বেটাৰী"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে)। বাকী আছে: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী।"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে)। সোঁ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> বেটাৰী।"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"সংযুক্ত হৈ আছে (অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"অডিঅ’ শ্বেয়াৰিং সমৰ্থন কৰে"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া), কেৱল বাওঁ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া), কেৱল সোঁ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"সক্ৰিয় হৈ আছে (কেৱল মিডিয়া), বাওঁ আৰু সোঁ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"হাৰ্ডৱেৰৰদ্বাৰা ত্বৰিত ৰেণ্ডাৰিং"</string> <string name="media_category" msgid="8122076702526144053">"মিডিয়া"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"নিৰীক্ষণ কৰি থকা হৈছে"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"কঠোৰ ম’ড সক্ষম কৰা হৈছে"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"যেতিয়া এপ্সমূহে মুখ্য থ্ৰেডত দীঘলীয়া কাৰ্যকলাপ চলায়, তেতিয়া স্ক্ৰীন ফ্লাশ্ব কৰক"</string> <string name="pointer_location" msgid="7516929526199520173">"পইণ্টাৰৰ অৱস্থান"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"ৱেবভিউ প্ৰয়োগ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"ৱেবভিউ প্ৰয়োগ ছেট কৰক"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"বাছনিটো এতিয়া আৰু মান্য় নহয়। আকৌ চেষ্টা কৰক।"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"চিত্ৰৰ ৰং ম’ড"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"এছআৰজিবি ব্যৱহাৰ কৰক"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"নিষ্ক্ৰিয় হৈ আছে"</string> diff --git a/packages/SettingsLib/res/values-az/arrays.xml b/packages/SettingsLib/res/values-az/arrays.xml index 52cf498e00ab..3b02070cce96 100644 --- a/packages/SettingsLib/res/values-az/arrays.xml +++ b/packages/SettingsLib/res/values-az/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Yalnız cihaz displeyi (defolt)"</item> + <item msgid="9161645858025071955">"Xarici displey"</item> + <item msgid="23651860565814477">"Ən son status paneli toxunuşu"</item> + <item msgid="7521112827893653392">"Fokus əsaslı"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Kölgəni yalnız cihaz displeyində göstərin"</item> + <item msgid="1955398604822147783">"Tək xarici displeydə kölgə göstərilsin"</item> + <item msgid="391477482416751568">"Ən son status paneli ilə interaksiya edilmiş displeydə kölgə göstərilsin"</item> + <item msgid="1746820128097981528">"Son fokuslanmış displeydə kölgə göstərilsin"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index 9013fb5bc324..aa939646c319 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ətraf mühit güncəllənmədi"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktiv (yalnız media). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiv (yalnız media). Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batareya."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Qoşulub (audio paylaşma dəstəklənir). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Qoşulub (audio paylaşma dəstəklənir). Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batareya."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Qoşulub (audio paylaşma dəstəklənir). Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Qoşulub (audio paylaşma dəstəklənir). Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batareya."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Qoşulub (audio paylaşma dəstəklənir)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (yalnız media)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Audio paylaşma dəstəklənir"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (yalnız media), yalnız sol"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (yalnız media), yalnız sağ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (yalnız media), sol və sağ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Renderinq aparat sürətlənməsi"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitorinq"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Ciddi rejim"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Uzun əməliyyatlar ərzində ekran işıqlandırılsın"</string> <string name="pointer_location" msgid="7516929526199520173">"Kursor yeri"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView servisi"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView servisini ayarlayın"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Bu seçim artıq etibarlı deyil. Yenidən cəhd edin."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Şəkil rəng rejimi"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB istifadə edin"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Deaktiv"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 7a00b96e0ed7..7f605006771f 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ažuriranje okruženja nije uspelo"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktivno (samo za medije). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktivno (samo za medije). Levo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Povezano (podržava deljenje zvuka), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Povezano (podržava deljenje zvuka), levo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Povezano (podržava deljenje zvuka). Levo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Povezano (podržava deljenje zvuka). Desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Povezano (podržava deljenje zvuka)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivan (samo za medije)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podržava deljenje zvuka"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivan (samo za medije), samo levo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivan (samo za medije), samo desno"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivan (samo za medije), levo i desno"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardverski ubrzano prikazivanje"</string> <string name="media_category" msgid="8122076702526144053">"Mediji"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Nadgledanje"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Omogućen je strogi režim"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Ekran treperi kada aplikacije obavljaju duge operacije na glavnoj niti"</string> <string name="pointer_location" msgid="7516929526199520173">"Lokacija pokazivača"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Primena WebView-a"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Podesite primenu WebView-a"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Ovaj izbor više nije važeći. Probajte ponovo."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Režim boja slika"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Koristi sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Onemogućeno je"</string> diff --git a/packages/SettingsLib/res/values-be/arrays.xml b/packages/SettingsLib/res/values-be/arrays.xml index 48c362768a8f..e33a71ea1c02 100644 --- a/packages/SettingsLib/res/values-be/arrays.xml +++ b/packages/SettingsLib/res/values-be/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Толькі дысплэй прылады (стандартна)"</item> + <item msgid="9161645858025071955">"Знешні дысплэй"</item> + <item msgid="23651860565814477">"Апошняе націсканне на панэль стану"</item> + <item msgid="7521112827893653392">"У залежнасці ад выкарыстання"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Паказваць шчыток толькі на дысплэі прылады"</item> + <item msgid="1955398604822147783">"Паказваць шчыток апавяшчэнняў на адным знешнім дысплэі"</item> + <item msgid="391477482416751568">"Паказваць шчыток апавяшчэнняў на дысплэі, на якім адбывалася апошняе ўзаемадзеянне з панэллю стану"</item> + <item msgid="1746820128097981528">"Паказваць шчыток апавяшчэнняў на дысплэі, які выкарыстоўваўся апошнім"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index 0ad8ac7502b0..50de9248baf2 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Не ўдалося абнавіць стан навакольных гукаў"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Выкарыстоўваецца (толькі для мультымедыя). Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Выкарыстоўваецца (толькі для мультымедыя). Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (левы навушнік), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (правы навушнік)."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Падключана (падтрымліваецца абагульванне аўдыя). Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Падключана (падтрымліваецца абагульванне аўдыя). Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (левы навушнік), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (правы навушнік)."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Падключана (падтрымліваецца абагульванне аўдыя). Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (левы навушнік)."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Падключана (падтрымліваецца абагульванне аўдыя). Зарад акумулятара: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (правы навушнік)."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Падключана (падтрымліваецца абагульванне аўдыя)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Выкарыстоўваецца (толькі для мультымедыя)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Падтрымліваецца абагульванне аўдыя"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Выкарыстоўваецца (толькі для мультымедыя), толькі левы навушнік"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Выкарыстоўваецца (толькі для мультымедыя), толькі правы навушнік"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Выкарыстоўваецца (толькі для мультымедыя), левы і правы навушнікі"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Апаратнае паскарэнне рэндэрынгу"</string> <string name="media_category" msgid="8122076702526144053">"Медыя"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Маніторынг"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Уключаны строгі рэжым"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Падсвечваць экран падчас доўгіх аперацый"</string> <string name="pointer_location" msgid="7516929526199520173">"Пазіцыя ўказальніка"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Рэалізацыя WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Наладзіць рэалізацыю WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Гэты варыянт больш не даступны. Паспрабуйце яшчэ раз."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Каляровы рэжым выявы"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Выкарыстоўваць sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Выключана"</string> diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml index 21dfa06644a3..fabd7d9623fb 100644 --- a/packages/SettingsLib/res/values-bg/arrays.xml +++ b/packages/SettingsLib/res/values-bg/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Само на екрана на устройството (по подразбиране)"</item> + <item msgid="9161645858025071955">"Външен екран"</item> + <item msgid="23651860565814477">"Последно докосване на лентата на състоянието"</item> + <item msgid="7521112827893653392">"Въз основа на фокуса"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Показване на падащия панел само на екрана на устройството"</item> + <item msgid="1955398604822147783">"Показване на падащия панел на един външен екран"</item> + <item msgid="391477482416751568">"Показване на падащия панел на екрана, с чиято лента на състоянието е взаимодействано последно"</item> + <item msgid="1746820128097981528">"Показване на падащия панел на екрана, върху който последно е бил поставен фокусът"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 8a87e57ffe93..c3c17833ea29 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Данните за околните звуци не бяха актуализирани"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Активно (само за мултимедия). Батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Активно (само за мултимедия). Л: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Д: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Свързано (поддържа споделяне на звука). Батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Свързано (поддържа споделяне на звука). Л: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Д: батерия – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Свързано (поддържа споделяне на звука). За ляво ухо. Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Свързано (поддържа споделяне на звука). За дясно ухо. Батерия: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Свързано (поддържа споделяне на звука)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активно (само за мултимедия)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Поддържа споделяне на звука"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активно (само за мултимедия), само лявата"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активно (само за мултимедия), само дясната"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активно (само за мултимедия), лявата и дясната"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Хардуерно ускорено изобразяване"</string> <string name="media_category" msgid="8122076702526144053">"Мултимедия"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Наблюдение"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Активиран строг режим"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Примигване на екрана при дълги операции в главната нишка"</string> <string name="pointer_location" msgid="7516929526199520173">"Mестопол. на показалеца"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Внедряване на WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Задаване на внедряването на WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Този избор вече не е валиден. Опитайте отново."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Цветови режим за снимките"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Използване на sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Деактивирано"</string> diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml index b27264d5541b..27fe25830aca 100644 --- a/packages/SettingsLib/res/values-bn/arrays.xml +++ b/packages/SettingsLib/res/values-bn/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"শুধুমাত্র ডিভাইসের ডিসপ্লে (ডিফল্ট)"</item> + <item msgid="9161645858025071955">"এক্সটার্নাল ডিসপ্লে"</item> + <item msgid="23651860565814477">"লেটেস্ট স্ট্যাটাস বার টাচ"</item> + <item msgid="7521112827893653392">"ফোকাস-ভিত্তিক"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"শুধুমাত্র ডিভাইসের ডিসপ্লেতে শেড দেখুন"</item> + <item msgid="1955398604822147783">"কোনও একটি বাইরের ডিসপ্লেতে শেড দেখুন"</item> + <item msgid="391477482416751568">"সেই ডিসপ্লেতে শেড দেখুন যেখানে যার স্ট্যাটাস বারে শেষ বার ইন্টার্যাকশন করা হয়েছে"</item> + <item msgid="1746820128097981528">"সেই ডিসপ্লেতে শেড দেখুন যেখানে শেষবার ফোকাস করা হয়েছে"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 1e7c7a227b8e..93b652124d8a 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"সারাউন্ডিং আপডেট করা যায়নি"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"চালু আছে (শুধুমাত্র মিডিয়া)। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ব্যাটারি।"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"চালু আছে (শুধুমাত্র মিডিয়া), বাঁদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ডানদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ব্যাটারি।"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ব্যাটারি।"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে), বাঁদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ডানদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ব্যাটারি।"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে)। বাঁদিক: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ব্যাটারি।"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে)। ডানদিকে: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ব্যাটারি।"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"কানেক্ট করা আছে (অডিও শেয়ারিংয়ে কাজ করে)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"চালু আছে (শুধুমাত্র মিডিয়া)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"অডিও শেয়ারিংয়ে কাজ করে"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"চালু আছে (শুধুমাত্র মিডিয়া), শুধুমাত্র বাঁদিক"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"চালু আছে (শুধুমাত্র মিডিয়া), শুধুমাত্র ডানদিক"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"চালু আছে (শুধুমাত্র মিডিয়া), বাঁদিক ও ডানদিক"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"হার্ডওয়্যার দ্বারা চালিত রেন্ডারিং"</string> <string name="media_category" msgid="8122076702526144053">"মিডিয়া"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"পর্যবেক্ষণে রাখা"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"স্ট্রিক্ট মোড চালু আছে"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"মুখ্য থ্রেডে অ্যাপগুলির দীর্ঘ কার্যকলাপের ক্ষেত্রে স্ক্রিন ফ্ল্যাশ করে"</string> <string name="pointer_location" msgid="7516929526199520173">"পয়েন্টারের লোকেশন"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"ওয়েবভিউ প্রয়োগ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"ওয়েবভিউ প্রয়োগ সেট করুন"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"এই পছন্দটি আর বৈধ নেই৷ আবার চেষ্টা করুন৷"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"ছবি রঙ মোড"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ব্যবহার করুন"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"অক্ষম হয়েছে"</string> diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml index 44bbfaf4d56e..f8fc6acc0acb 100644 --- a/packages/SettingsLib/res/values-bs/arrays.xml +++ b/packages/SettingsLib/res/values-bs/arrays.xml @@ -291,14 +291,14 @@ <string-array name="shade_display_awareness_entries"> <item msgid="816770658383209617">"Samo zaslon uređaja (zadano)"</item> <item msgid="9161645858025071955">"Vanjski ekran"</item> - <item msgid="23651860565814477">"Najnoviji dodir trake statusa"</item> - <item msgid="7521112827893653392">"Na temelju fokusa"</item> + <item msgid="23651860565814477">"Posljednji dodir na statusnu traku"</item> + <item msgid="7521112827893653392">"Na osnovu fokusa"</item> </string-array> <string-array name="shade_display_awareness_summaries"> <item msgid="2964753205732912921">"Prikaži sjenu samo na ekranu uređaja"</item> - <item msgid="1955398604822147783">"Prikaži sjenčanje na jednom vanjskom zaslonu"</item> - <item msgid="391477482416751568">"Prikaži sjenčanje na zaslonu na kojem je posljednje stupljeno u interakciju s trakom statusa"</item> - <item msgid="1746820128097981528">"Prikaži sjenčanje na posljednjem fokusiranom zaslonu"</item> + <item msgid="1955398604822147783">"Prikaži sjenu na jednom vanjskom ekranu"</item> + <item msgid="391477482416751568">"Prikaži sjenu na posljednjem ekranu na kojem se stupalo u interakciju sa statusnom trakom"</item> + <item msgid="1746820128097981528">"Prikaži sjenu na posljednjem fokusiranom ekranu"</item> </string-array> <string-array name="shade_display_awareness_values"> <item msgid="3055776101992426514">"default_display"</item> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 756a3268ec98..abb0775eb9ab 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ažuriranje okruženja nije uspjelo"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktivno (samo za medijski sadržaj). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktivno (samo za medijski sadržaj). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterije, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Povezano (podržava dijeljenje zvuka). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Povezano (podržava dijeljenje zvuka). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> baterije, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Povezano (podržava dijeljenje zvuka). Lijevo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Povezano (podržava dijeljenje zvuka). Desno: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Povezano (podržava dijeljenje zvuka)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivno (samo za medijski sadržaj)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podržava dijeljenje zvuka"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivno (samo za medijski sadržaj), samo lijevo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivno (samo za medijski sadržaj), samo desno"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivno (samo za medijski sadržaj), lijevo i desno"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardverski ubrzano prikazivanje"</string> <string name="media_category" msgid="8122076702526144053">"Mediji"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Praćenje"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Omogući strogi način rada"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Ekran bljeska kada aplikacije vrše duge operacije u glavnoj niti"</string> <string name="pointer_location" msgid="7516929526199520173">"Lokacija pokazivača"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Postavljanje WebViewa"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Podesi WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Ovaj izbor više ne vrijedi. Pokušajte ponovo."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Način rada boja slika"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Koristi sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Onemogućeno"</string> diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml index f19551c5194b..8f1f630eabf7 100644 --- a/packages/SettingsLib/res/values-ca/arrays.xml +++ b/packages/SettingsLib/res/values-ca/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Només a la pantalla del dispositiu (opció predeterminada)"</item> + <item msgid="9161645858025071955">"Pantalla externa"</item> + <item msgid="23651860565814477">"Darrer toc a la barra d\'estat"</item> + <item msgid="7521112827893653392">"Basat en l\'enfocament"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Mostra l\'ombra només a la pantalla del dispositiu"</item> + <item msgid="1955398604822147783">"Mostra l\'àrea en una sola pantalla externa"</item> + <item msgid="391477482416751568">"Mostra l\'àrea a la pantalla amb què s\'ha interaccionat per darrera vegada a la barra d\'estat"</item> + <item msgid="1746820128097981528">"Mostra l\'àrea a la darrera pantalla en què s\'hagi posat el focus"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 05480999b3e0..ed49307c4093 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"No s\'ha pogut actualitzar l\'entorn"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Actiu (només contingut multimèdia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Actiu (només contingut multimèdia), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Connectat (admet compartició d\'àudio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Connectat (admet compartició d\'àudio), E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Connectat (admet compartició d\'àudio). Esquerre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Connectat (admet compartició d\'àudio). Dret: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Connectat (admet compartició d\'àudio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Actiu (només contingut multimèdia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Admet compartició d\'àudio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Actiu (només contingut multimèdia), només esquerre"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Actiu (només contingut multimèdia), només dret"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Actiu (només contingut multimèdia), esquerre i dret"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Renderització accelerada per maquinari"</string> <string name="media_category" msgid="8122076702526144053">"Multimèdia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Supervisió"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Mode estricte activat"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Il·lumina la pantalla quan les aplicacions facin operacions llargues al fil principal"</string> <string name="pointer_location" msgid="7516929526199520173">"Ubicació del punter"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementació de WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Estableix implementació de WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Aquesta opció ja no és vàlida. Torna-ho a provar."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Mode de color de la imatge"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Utilitza sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desactivat"</string> diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml index ad1cafd2dd2d..152cd8346b8c 100644 --- a/packages/SettingsLib/res/values-cs/arrays.xml +++ b/packages/SettingsLib/res/values-cs/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Pouze zobrazení zařízení (výchozí)"</item> + <item msgid="9161645858025071955">"Externí displej"</item> + <item msgid="23651860565814477">"Poslední dotknutí se stavového řádku"</item> + <item msgid="7521112827893653392">"Výběr"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Zobrazovat panel pouze na displeji zařízení"</item> + <item msgid="1955398604822147783">"Zobrazovat panel na jednom externím displeji"</item> + <item msgid="391477482416751568">"Zobrazovat panel na displeji, na kterém uživatel naposledy interagoval se stavovým řádkem"</item> + <item msgid="1746820128097981528">"Zobrazovat panel na displeji, který byl naposledy vybrán"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index a774a1d9bffc..7ea6e430cb09 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Okolí se nepodařilo aktualizovat"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktivní (pouze média). Baterie: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktivní (pouze média), baterie: L <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Připojeno (podporuje sdílení zvuku), baterie: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Připojeno (podporuje sdílení zvuku), baterie: L <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Připojeno (podporuje sdílení zvuku). Levá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterie"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Připojeno (podporuje sdílení zvuku). Pravá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterie."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Připojeno (podporuje sdílení zvuku)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivní (pouze média)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podporuje sdílení zvuku"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivní (pouze média), pouze levé"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivní (pouze média), pouze pravé"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivní (pouze média), levé a pravé"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardwarově urychlené vykreslování"</string> <string name="media_category" msgid="8122076702526144053">"Média"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Sledování"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Přísný režim aktivován"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Rozblikat obrazovku při dlouhých operacích hlavního vlákna"</string> <string name="pointer_location" msgid="7516929526199520173">"Umístění ukazatele"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementace WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Nastavte implementaci WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Tato volba již není platná. Zkuste to znovu."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Režim barev obrázku"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Použije se barevný prostor sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Vypnuto"</string> diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml index ed457756abfa..aff59c23fc00 100644 --- a/packages/SettingsLib/res/values-da/arrays.xml +++ b/packages/SettingsLib/res/values-da/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Kun på enhedens skærm (standard)"</item> + <item msgid="9161645858025071955">"Ekstern skærm"</item> + <item msgid="23651860565814477">"Seneste tryk på statusbjælken"</item> + <item msgid="7521112827893653392">"Fokusbaseret"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Vis kun skygge på enhedens skærm"</item> + <item msgid="1955398604822147783">"Vis skygge på en enkelt ekstern skærm"</item> + <item msgid="391477482416751568">"Vis skygge på den skærm, hvor der sidst blev interageret med statusbjælken"</item> + <item msgid="1746820128097981528">"Vis skygge på den skærm, der sidst var i fokus"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index d7aa9b1dd71a..4aad2a2b8ac6 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Omgivelserne kunne ikke opdateres"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktiveret (kun for medier). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiveret (kun for medier), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Forbundet (understøtter lyddeling). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Forbundet (understøtter lyddeling), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Forbundet (understøtter lyddeling). Venstre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Forbundet (understøtter lyddeling). Højre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Forbundet (understøtter lyddeling)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiveret (kun for medier)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Understøtter lyddeling"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiveret (kun for medier), kun venstre"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiveret (kun for medier), kun højre"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiveret (kun for medier), venstre og højre"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardware-accelereret gengivelse"</string> <string name="media_category" msgid="8122076702526144053">"Medie"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Overvågning"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Striks tilstand aktiveret"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Blink med skærmen, når apps foretager handlinger på hovedtråd"</string> <string name="pointer_location" msgid="7516929526199520173">"Markørens lokation"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Konfigurer WebView-implementering"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Dette valg er ikke længere gyldigt. Prøv igen."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Farvetilstand for billeder"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Brug sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Deaktiveret"</string> diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml index 924718a37a4d..6dc8754f4987 100644 --- a/packages/SettingsLib/res/values-de/arrays.xml +++ b/packages/SettingsLib/res/values-de/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Nur Gerätedisplay (Standard)"</item> + <item msgid="9161645858025071955">"Externes Display"</item> + <item msgid="23651860565814477">"Letzte Berührung der Statusleiste"</item> + <item msgid="7521112827893653392">"Fokusbasiert"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Leiste nur auf dem Display des Geräts anzeigen"</item> + <item msgid="1955398604822147783">"Leiste auf einem einzigen externen Display anzeigen"</item> + <item msgid="391477482416751568">"Leiste auf dem Display anzeigen, auf dem zuletzt mit der Statusleiste interagiert wurde"</item> + <item msgid="1746820128097981528">"Leiste auf dem zuletzt fokussierten Display anzeigen"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 73268c5aa6b2..55cae9699b47 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Status der Umgebungsgeräusche konnte nicht aktualisiert werden"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktiv (nur Medien). Akku: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiv (nur Medien). Akku links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Akku rechts: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Verbunden (unterstützt Audiofreigabe). Akku: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Verbunden (unterstützt Audiofreigabe). Akku links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Akku rechts: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Verbunden (unterstützt Audiofreigabe). Akku links: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Verbunden (unterstützt Audiofreigabe). Akku rechts: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Verbunden (unterstützt Audiofreigabe)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (nur Medien)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Unterstützt Audiofreigabe"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (nur Medien), nur links"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (nur Medien), nur rechts"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (nur Medien), links und rechts"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardwarebeschleunigtes Rendering"</string> <string name="media_category" msgid="8122076702526144053">"Medien"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoring"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strikter Modus aktiviert"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Bei langen App-Vorgängen im Hauptthread blinkt Bildschirm"</string> <string name="pointer_location" msgid="7516929526199520173">"Zeigerposition"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-Implementierung"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView-Implementierung festlegen"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Diese Auswahl ist nicht mehr gültig. Bitte versuche es noch einmal."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Farbmodus für Bilder"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB verwenden"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Deaktiviert"</string> diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml index 41aefc097bcd..33e23906ca66 100644 --- a/packages/SettingsLib/res/values-el/arrays.xml +++ b/packages/SettingsLib/res/values-el/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Μόνο οθόνη συσκευής (Προεπιλογή)"</item> + <item msgid="9161645858025071955">"Εξωτερική οθόνη"</item> + <item msgid="23651860565814477">"Τελευταίο άγγιγμα της γραμμής κατάστασης"</item> + <item msgid="7521112827893653392">"Με εστίαση"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Εμφάνιση σκίασης μόνο στην οθόνη συσκευής"</item> + <item msgid="1955398604822147783">"Εμφάνιση σκίασης σε εξωτερική οθόνη"</item> + <item msgid="391477482416751568">"Εμφάνιση σκίασης στην οθόνη στην οποία έγινε η τελευταία αλληλεπίδραση με τη γραμμή κατάστασης"</item> + <item msgid="1746820128097981528">"Εμφάνιση σκίασης στην τελευταία οθόνη με εστίαση"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 209b7820b59a..6b6b7fbcab93 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Δεν ήταν δυνατή η ενημέρωση των ήχων περιβάλλοντος"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Ενεργό (μόνο για μέσα). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Ενεργό (μόνο για μέσα). Α: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Δ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> μπαταρία."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου). Α: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Δ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> μπαταρία."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου). Αριστερά: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου). Δεξιά: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> μπαταρία."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Συνδεδεμένο (υποστηρίζει κοινή χρήση ήχου)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ενεργό (μόνο για μέσα)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Υποστηρίζει κοινή χρήση ήχου"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ενεργό (μόνο για μέσα), μόνο αριστερό"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ενεργό (μόνο για μέσα), μόνο δεξί"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ενεργό (μόνο για μέσα), αριστερό και δεξί"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Απόδοση με επιτάχυνση από υλικό εξοπλισμό"</string> <string name="media_category" msgid="8122076702526144053">"Μέσα"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Παρακολούθηση"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Ενεργ. αυστηρής λειτουργ."</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Αναβ. οθόνη σε εκτέλεση μεγάλων λειτ.σε κύριο νήμα"</string> <string name="pointer_location" msgid="7516929526199520173">"Θέση δείκτη"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Υλοποίηση WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Ορισμός υλοποίησης WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Αυτή η επιλογή δεν είναι πια έγκυρη. Δοκιμάστε ξανά."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Λειτουργία χρώματος εικόνας"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Χρήση sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Απενεργοποιημένο"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml index 6c7a7ffb58ed..b53ad98fa245 100644 --- a/packages/SettingsLib/res/values-en-rAU/arrays.xml +++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Device display only (default)"</item> + <item msgid="9161645858025071955">"External display"</item> + <item msgid="23651860565814477">"Latest status bar touch"</item> + <item msgid="7521112827893653392">"Focus-based"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Show shade on device display only"</item> + <item msgid="1955398604822147783">"Show shade on single external display"</item> + <item msgid="391477482416751568">"Show shade on display which last had its status bar interacted with"</item> + <item msgid="1746820128097981528">"Show shade on last focused display"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index d965c6522a9d..a8119602b651 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Couldn\'t update surroundings"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Active (media only). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Active (media only). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Connected (supports audio sharing). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Connected (supports audio sharing). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Connected (supports audio sharing). Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Connected (supports audio sharing). Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Connected (supports audio sharing)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Active (media only)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supports audio sharing"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Active (media only), left only"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Active (media only), right only"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Active (media only), left and right"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardware accelerated rendering"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoring"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strict mode enabled"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Flash screen when apps do long operations on main thread"</string> <string name="pointer_location" msgid="7516929526199520173">"Pointer location"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Set WebView implementation"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"This choice is no longer valid. Try again."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Picture colour mode"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Use sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Disabled"</string> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index 748d7b11d7ed..a12b46c06300 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -113,13 +113,23 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Couldn’t update surroundings"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Active (media only). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Active (media only). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> + <string name="bluetooth_guest_battery_level" msgid="2820003593899467676">"Guest device. <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> + <string name="bluetooth_guest_battery_level_untethered" msgid="5404013822067644960">"Guest device. L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> + <string name="bluetooth_guest_media_only_battery_level" msgid="7928347900623812299">"Guest device (media only). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> + <string name="bluetooth_guest_media_only_battery_level_untethered" msgid="4458143141394300892">"Guest device (media only). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Connected (supports audio sharing). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Connected (supports audio sharing). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Connected (supports audio sharing). Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Connected (supports audio sharing). Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Connected (supports audio sharing)"</string> + <string name="bluetooth_guest_battery_level_lea_support" msgid="8098327939585013928">"Guest device (supports audio sharing). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> + <string name="bluetooth_guest_battery_level_untethered_lea_support" msgid="3701035025565668360">"Guest device (supports audio sharing). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> + <string name="bluetooth_guest_no_battery_level_lea_support" msgid="2977038548753103470">"Guest device (supports audio sharing)"</string> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Active (media only)"</string> + <string name="bluetooth_guest_no_battery_level" msgid="9122974160381136920">"Guest device"</string> + <string name="bluetooth_guest_media_only_no_battery_level" msgid="7666347601796705721">"Guest device (media only)"</string> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supports audio sharing"</string> + <string name="bluetooth_guest_saved_device_lea_support" msgid="5621291599518569876">"Guest device. Supports audio sharing"</string> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Active (media only), left only"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Active (media only), right only"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Active (media only), left and right"</string> @@ -376,6 +386,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardware accelerated rendering"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoring"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strict mode enabled"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Flash screen when apps do long operations on main thread"</string> <string name="pointer_location" msgid="7516929526199520173">"Pointer location"</string> @@ -470,6 +482,9 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Set WebView implementation"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"This choice is no longer valid. Try again."</string> + <string name="webview_launch_devtools_title" msgid="8009687433555367112">"WebView DevTools"</string> + <string name="webview_launch_devtools_no_package" msgid="3182544553665113721">"WebView package not found."</string> + <string name="webview_launch_devtools_no_activity" msgid="4066006313619617140">"Could not launch DevTools."</string> <string name="picture_color_mode" msgid="1013807330552931903">"Picture color mode"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Use sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Disabled"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml index 6c7a7ffb58ed..b53ad98fa245 100644 --- a/packages/SettingsLib/res/values-en-rGB/arrays.xml +++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Device display only (default)"</item> + <item msgid="9161645858025071955">"External display"</item> + <item msgid="23651860565814477">"Latest status bar touch"</item> + <item msgid="7521112827893653392">"Focus-based"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Show shade on device display only"</item> + <item msgid="1955398604822147783">"Show shade on single external display"</item> + <item msgid="391477482416751568">"Show shade on display which last had its status bar interacted with"</item> + <item msgid="1746820128097981528">"Show shade on last focused display"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index d965c6522a9d..a8119602b651 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Couldn\'t update surroundings"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Active (media only). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Active (media only). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Connected (supports audio sharing). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Connected (supports audio sharing). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Connected (supports audio sharing). Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Connected (supports audio sharing). Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Connected (supports audio sharing)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Active (media only)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supports audio sharing"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Active (media only), left only"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Active (media only), right only"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Active (media only), left and right"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardware accelerated rendering"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoring"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strict mode enabled"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Flash screen when apps do long operations on main thread"</string> <string name="pointer_location" msgid="7516929526199520173">"Pointer location"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Set WebView implementation"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"This choice is no longer valid. Try again."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Picture colour mode"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Use sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Disabled"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml index 6c7a7ffb58ed..b53ad98fa245 100644 --- a/packages/SettingsLib/res/values-en-rIN/arrays.xml +++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Device display only (default)"</item> + <item msgid="9161645858025071955">"External display"</item> + <item msgid="23651860565814477">"Latest status bar touch"</item> + <item msgid="7521112827893653392">"Focus-based"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Show shade on device display only"</item> + <item msgid="1955398604822147783">"Show shade on single external display"</item> + <item msgid="391477482416751568">"Show shade on display which last had its status bar interacted with"</item> + <item msgid="1746820128097981528">"Show shade on last focused display"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index d965c6522a9d..a8119602b651 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Couldn\'t update surroundings"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Active (media only). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Active (media only). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Connected (supports audio sharing). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Connected (supports audio sharing). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Connected (supports audio sharing). Left: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Connected (supports audio sharing). Right: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Connected (supports audio sharing)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Active (media only)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supports audio sharing"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Active (media only), left only"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Active (media only), right only"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Active (media only), left and right"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardware accelerated rendering"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoring"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strict mode enabled"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Flash screen when apps do long operations on main thread"</string> <string name="pointer_location" msgid="7516929526199520173">"Pointer location"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Set WebView implementation"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"This choice is no longer valid. Try again."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Picture colour mode"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Use sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Disabled"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml index 5894975de1ba..2f1b14d1469c 100644 --- a/packages/SettingsLib/res/values-es-rUS/arrays.xml +++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Solo en la pantalla del dispositivo (predeterminado)"</item> + <item msgid="9161645858025071955">"Pantalla externa"</item> + <item msgid="23651860565814477">"Última interacción con la barra de estado"</item> + <item msgid="7521112827893653392">"Basado en el enfoque"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Mostrar sobra solo en la pantalla del dispositivo"</item> + <item msgid="1955398604822147783">"Mostrar panel en una sola pantalla externa"</item> + <item msgid="391477482416751568">"Mostrar el panel de la última pantalla en la que se interactuó con su barra de estado"</item> + <item msgid="1746820128097981528">"Mostrar el panel en la última pantalla enfocada"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index acd67908dfba..6c3c98aa5702 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"No se pudo actualizar el sonido envolvente"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Activado (solo para contenido multimedia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Activo (solo para contenido multimedia); I: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>; D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (admite el uso compartido de audio); <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (admite el uso compartido de audio); I: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>; D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (admite el uso compartido de audio). Izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (admite el uso compartido de audio). Derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (admite el uso compartido de audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activo (solo para contenido multimedia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Admite el uso compartido de audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activo (solo para contenido multimedia); solo izquierdo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activo (solo para contenido multimedia); solo derecho"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activo (solo para contenido multimedia); izquierdo y derecho"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Renderización acelerada por hardware"</string> <string name="media_category" msgid="8122076702526144053">"Multimedia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Supervisión"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Modo estricto"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Parpadear si aplicaciones tardan en proceso principal"</string> <string name="pointer_location" msgid="7516929526199520173">"Ubicación del puntero"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Configurar la implementación de WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opción ya no es válida. Vuelve a intentarlo."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modo de color de la imagen"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Usa sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Inhabilitado"</string> diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml index 1e8c6614280c..9031cc3c59db 100644 --- a/packages/SettingsLib/res/values-es/arrays.xml +++ b/packages/SettingsLib/res/values-es/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Solo en la pantalla del dispositivo (predeterminado)"</item> + <item msgid="9161645858025071955">"Pantalla externa"</item> + <item msgid="23651860565814477">"Toque más reciente en la barra de estado"</item> + <item msgid="7521112827893653392">"Basado en el enfoque"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Mostrar el panel solo en la pantalla del dispositivo"</item> + <item msgid="1955398604822147783">"Mostrar el panel en una sola pantalla externa"</item> + <item msgid="391477482416751568">"Mostrar el panel en la pantalla en la que se haya interactuado por última vez con la barra de estado"</item> + <item msgid="1746820128097981528">"Mostrar el panel en la última pantalla enfocada"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 00b987c75602..b91c9b420cf0 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"No se han podido actualizar los alrededores"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Activo (solo multimedia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Activo (solo multimedia). Izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. Derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (permite compartir audio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (admite Compartir audio). Izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. Derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (admite Compartir audio). Izquierdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (admite Compartir audio). Derecho: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (admite Compartir audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activo (solo multimedia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Permite compartir audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activo (solo multimedia), solo el izquierdo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activo (solo multimedia), solo el derecho"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activo (solo multimedia), izquierdo y derecho"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Renderización acelerada por hardware"</string> <string name="media_category" msgid="8122076702526144053">"Multimedia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Supervisión"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Modo Estricto habilitado"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Hace parpadear la pantalla si las aplicaciones tardan mucho en el subproceso principal"</string> <string name="pointer_location" msgid="7516929526199520173">"Ubicación del puntero"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Establecer implementación de WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opción ya no está disponible. Vuelve a intentarlo."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modo de color de imagen"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Utiliza sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Inhabilitado"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index b442ed3c6578..8c5d7fe4a96b 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ümbritsevate helide seadeid ei saanud värskendada"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktiivne (ainult meedia). Aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiivne (ainult meedia). Aku: V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Ühendatud (toetab heli jagamist). Aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Ühendatud (toetab heli jagamist). Aku: V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Ühendatud (toetab heli jagamist). Vasak: aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Ühendatud (toetab heli jagamist). Parem: aku <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Ühendatud (toetab heli jagamist)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiivne (ainult meedia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Toetab heli jagamist"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiivne (ainult meedia), ainult vasak"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiivne (ainult meedia), ainult parem"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiivne (ainult meedia), vasak ja parem"</string> @@ -129,7 +149,7 @@ <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Sisendseade"</string> <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Juurdepääs internetile"</string> <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Luba juurdepääs kontaktidele ja kõneajale"</string> - <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Teavet kasutatakse kõne teadaannete ja muu jaoks"</string> + <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Teavet kasutatakse kõne teadaannete ja muu jaoks."</string> <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Interneti-ühenduse jagamine"</string> <string name="bluetooth_profile_map" msgid="8907204701162107271">"Tekstsõnumid"</string> <string name="bluetooth_profile_sap" msgid="8304170950447934386">"Juurdepääs SIM-ile"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Riistvarakiirendusega renderdamine"</string> <string name="media_category" msgid="8122076702526144053">"Meedia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Jälgimine"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Range režiim on lubatud"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Ekraan vilgub, kui rakendused teevad pealõimes pikki toiminguid"</string> <string name="pointer_location" msgid="7516929526199520173">"Kursori asukoht"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView\' rakendamine"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView\' rakendamise seadistamine"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"See valik ei kehti enam. Proovige uuesti."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Pildi värvirežiim"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB kasutamine"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Keelatud"</string> diff --git a/packages/SettingsLib/res/values-eu/arrays.xml b/packages/SettingsLib/res/values-eu/arrays.xml index a1528c2a1e7d..616b12f6712f 100644 --- a/packages/SettingsLib/res/values-eu/arrays.xml +++ b/packages/SettingsLib/res/values-eu/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Gailuaren pantailan soilik (lehenetsia)"</item> + <item msgid="9161645858025071955">"Kanpoko pantailan"</item> + <item msgid="23651860565814477">"Egoera-barraren azken ukitzea"</item> + <item msgid="7521112827893653392">"Fokuaren arabera"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Erakutsi itzalak gailuaren pantailan soilik"</item> + <item msgid="1955398604822147783">"Erakutsi itzala kanpoko pantaila bakar batean"</item> + <item msgid="391477482416751568">"Erakutsi itzala egoera-barran interakzio bat izan duen azken pantailan"</item> + <item msgid="1746820128097981528">"Erakutsi itzala fokuratutako azken pantailan"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 1c422b656347..a1e46649c3cf 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ezin izan da eguneratu ingurunea"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktibo (multimedia-edukia soilik). Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktibo (multimedia-edukia soilik). L aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. R aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Konektatuta (audioa partekatzeko eginbidea onartzen du). Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Konektatuta (audioa partekatzeko eginbidea onartzen du). L aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. R aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Konektatuta (audioa partekatzeko eginbidea onartzen du). Ezkerreko aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Konektatuta (audioa partekatzeko eginbidea onartzen du). Eskuineko aldearen bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Konektatuta (audioa partekatzeko eginbidea onartzen du)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktibo (multimedia-edukia soilik)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Audioa partekatzeko eginbidea onartzen du"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktibo (multimedia-edukia soilik); ezkerreko aldea soilik"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktibo (multimedia-edukia soilik); eskuineko aldea soilik"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktibo (multimedia-edukia soilik); ezkerreko eta eskuineko aldeak"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardware bidez azeleratutako errendatzea"</string> <string name="media_category" msgid="8122076702526144053">"Multimedia-edukia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Kontrola"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Modu zorrotza gaituta"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Distirarazi hari nagusian eragiketa luzeak egitean"</string> <string name="pointer_location" msgid="7516929526199520173">"Erakuslearen kokapena"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Ezarri WebView inplementazioa"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Jada ez dago erabilgarri aukera hori. Saiatu berriro."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Irudiaren kolore modua"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Erabili sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desgaituta"</string> diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml index d7face8672af..84217268c219 100644 --- a/packages/SettingsLib/res/values-fa/arrays.xml +++ b/packages/SettingsLib/res/values-fa/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"۲"</item> <item msgid="4779928470672877922">"۳"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"فقط نمایشگر دستگاه (پیشفرض)"</item> + <item msgid="9161645858025071955">"نمایشگر خارجی"</item> + <item msgid="23651860565814477">"آخرین لمس نوار وضعیت"</item> + <item msgid="7521112827893653392">"کانونیمحور"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"نمایش سایه فقط در نمایشگر دستگاه"</item> + <item msgid="1955398604822147783">"نمایش سایه در یک نمایشگر خارجی"</item> + <item msgid="391477482416751568">"نمایش سایه در نمایشگری که کاربر آخرین بار با نوار وضعیت آن تعامل داشته است"</item> + <item msgid="1746820128097981528">"نمایش سایه در آخرین نمایشگر کانونیشده"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"نمایشگر_پیشفرض"</item> + <item msgid="774789415968826925">"هر_نمایشگر_خارجی"</item> + <item msgid="7880769915418638436">"آخرین_لمس_نوار_وضعیت"</item> + <item msgid="4313165186636015195">"نمایشگر_کانونیشده"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index b1f76fb5a787..c939180e6f5a 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"پیرامون بهروز نشد"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"فعال (فقط رسانه). باتری: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"فعال (فقط رسانه). باتری چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، باتری راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"متصل (از اشتراک صدا پشتیبانی میکند)، باتری: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"متصل (از اشتراک صدا پشتیبانی میکند)، باتری چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، باتری راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"متصل (از اشتراک صدا پشتیبانی میکند). باتری چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"متصل (از اشتراک صدا پشتیبانی میکند). باتری راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"متصل (از اشتراک صدا پشتیبانی میکند)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"فعال (فقط رسانه)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"از اشتراک صدا پشتیبانی میکند"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"فعال (فقط رسانه)، فقط چپ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"فعال (فقط رسانه)، فقط راست"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"فعال (فقط رسانه)، چپ و راست"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"پردازش سختافزاری سریع"</string> <string name="media_category" msgid="8122076702526144053">"رسانه"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"نظارت"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"حالت شدید فعال شد"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"چشمک زدن صفحه هنگام انجام عملیات طولانی توسط برنامهها در رشته اصلی"</string> <string name="pointer_location" msgid="7516929526199520173">"محل اشارهگر"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"اجرای وبنما"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"تنظیم اجرای وبنما"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"این انتخاب دیگر معتبر نیست. دوباره امتحان کنید."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"حالت رنگ عکس"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"استفاده از sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"غیر فعال"</string> diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml index a10dfbe7a2f9..9779c6afc5f8 100644 --- a/packages/SettingsLib/res/values-fi/arrays.xml +++ b/packages/SettingsLib/res/values-fi/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Vain laitteen näyttö (oletus)"</item> + <item msgid="9161645858025071955">"Ulkoinen näyttö"</item> + <item msgid="23651860565814477">"Viimeisin tilapalkin kosketus"</item> + <item msgid="7521112827893653392">"Kohdistusperustainen"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Näytä ilmoitusalue vain laitteen näytöllä"</item> + <item msgid="1955398604822147783">"Näytä ilmoitusalue yhdellä ulkoisella näytöllä"</item> + <item msgid="391477482416751568">"Näytä ilmoitusalue näytöllä, jolla tilapalkkiin on viimeksi reagoitu"</item> + <item msgid="1746820128097981528">"Näytä ilmoitusalue viimeksi kohdistetulla näytöllä"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index b59aa3019f67..d2228824cd04 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ympäristön päivittäminen epäonnistui"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktiivinen (vain media). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> virtaa."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiivinen (vain media). V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, O: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> virtaa."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Yhdistetty (tukee audionjakoa). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> virtaa."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Yhdistetty (tukee audionjakoa). V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> virtaa, O: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> virtaa."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Yhdistetty (tukee audionjakoa). Vasen: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> virtaa."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Yhdistetty (tukee audionjakoa). Oikea: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> virtaa."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Yhdistetty (tukee audionjakoa)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiivinen (vain media)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Tukee audionjakoa"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiivinen (vain media), vain vasen"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiivinen (vain media), vain oikea"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiivinen (vain media), vasen ja oikea"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Laitteistokiihdytetty hahmonnus"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Valvonta"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Tiukka tila käytössä"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Vilkuta näyttöä sovellusten tehdessä pitkiä toimia"</string> <string name="pointer_location" msgid="7516929526199520173">"Osoittimen sijainti"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-käyttöönotto"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Määritä WebView-käyttöönotto"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Tämä valinta ei ole enää saatavilla. Yritä uudestaan."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Kuvien värit"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Ota sRGB käyttöön"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Poistettu käytöstä"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml index 9eec65d3119c..f5be65538ee3 100644 --- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml +++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Écran de l\'appareil seulement (par défaut)"</item> + <item msgid="9161645858025071955">"Écran externe"</item> + <item msgid="23651860565814477">"Dernière barre d\'état tactile"</item> + <item msgid="7521112827893653392">"Affichage mis en évidence"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Afficher le volet sur l\'écran de l\'appareil seulement"</item> + <item msgid="1955398604822147783">"Afficher le volet sur un seul écran externe"</item> + <item msgid="391477482416751568">"Afficher le volet sur l\'écran avec lequel la barre d\'état a interagi en dernier"</item> + <item msgid="1746820128097981528">"Afficher le volet sur le dernier affichage mis en évidence"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index 99ba8b0ba5df..b03e6cb372e2 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Impossible de mettre à jour les sons de l\'environnement"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Actif (contenu multimédia uniquement). Pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Actif (contenu multimédia uniquement). G. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Connecté (prise en charge du partage audio). Pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Connecté (prise en charge du partage audio). G. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D. : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Connecté (prise en charge du partage audio). Gauche : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Connecté (prise en charge du partage audio). Droite : pile à <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Connecté (prise en charge du partage audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Actif (contenu multimédia uniquement)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Prise en charge du partage audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Actif (contenu multimédia uniquement), côté gauche seulement"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Actif (contenu multimédia uniquement), côté droit seulement"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Actif (contenu multimédia uniquement), côtés gauche et droit"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Accélération matérielle"</string> <string name="media_category" msgid="8122076702526144053">"Médias"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Surveillance"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Mode Strict activé"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Afficher un cadre rouge si le fil principal reste occupé"</string> <string name="pointer_location" msgid="7516929526199520173">"Emplacement du curseur"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Définir la mise en œuvre WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Ce choix n\'est plus valide. Réessayez."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Mode couleur des images"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Utiliser sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Désactivé"</string> diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml index 37875095b6dc..3cf68b2e0cd5 100644 --- a/packages/SettingsLib/res/values-fr/arrays.xml +++ b/packages/SettingsLib/res/values-fr/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Écran de l\'appareil uniquement (par défaut)"</item> + <item msgid="9161645858025071955">"Écran externe"</item> + <item msgid="23651860565814477">"Dernière interaction avec la barre d\'état"</item> + <item msgid="7521112827893653392">"Basé sur la sélection"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Afficher le volet sur l\'écran de l\'appareil uniquement"</item> + <item msgid="1955398604822147783">"Afficher le volet sur un seul écran externe"</item> + <item msgid="391477482416751568">"Afficher le volet sur l\'écran avec lequel la barre d\'état a été utilisée en dernier lieu"</item> + <item msgid="1746820128097981528">"Afficher le volet sur le dernier écran avec lequel l\'utilisateur a interagi"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index ba77d87100c2..4440126078fd 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Impossible de mettre à jour le mode Sons environnants"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Actif (multimédia uniquement). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Actif (multimédia uniquement). Gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batterie, droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batterie."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Connecté (compatible avec le partage audio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Connecté (compatible avec le partage audio). Gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batterie, droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batterie."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Connecté (compatible avec le partage audio). Gauche : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Connecté (compatible avec le partage audio). Droit : <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batterie."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Connecté (compatible avec le partage audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activé (multimédia uniquement)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Compatible avec le partage audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activé (multimédia uniquement), gauche uniquement"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activé (multimédia uniquement), droit uniquement"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activé (multimédia uniquement), gauche et droit"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Rendu accéléré par le matériel"</string> <string name="media_category" msgid="8122076702526144053">"Multimédia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Suivi"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Mode Strict activé"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Faire clignoter l\'écran si le thread principal reste occupé"</string> <string name="pointer_location" msgid="7516929526199520173">"Emplacement du curseur"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implémentation WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Définir la mise en œuvre WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Ce choix n\'est plus valide. Réessayez."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Mode de couleur des images"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Utiliser sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Désactivé"</string> diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml index 9307ba7e747a..76441f94693d 100644 --- a/packages/SettingsLib/res/values-gl/arrays.xml +++ b/packages/SettingsLib/res/values-gl/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Só pantalla do dispositivo (opción predeterminada)"</item> + <item msgid="9161645858025071955">"Pantalla externa"</item> + <item msgid="23651860565814477">"Último toque na barra de estado"</item> + <item msgid="7521112827893653392">"En función do enfoque"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Mostrar panel despregable só na pantalla do dispositivo"</item> + <item msgid="1955398604822147783">"Mostrar panel despregable nunha única pantalla externa"</item> + <item msgid="391477482416751568">"Mostrar panel despregable na pantalla na que tivo lugar a última interacción coa barra de estado"</item> + <item msgid="1746820128097981528">"Mostrar panel despregable na última pantalla enfocada"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"pantalla_predeterminada"</item> + <item msgid="774789415968826925">"calquera_pantalla_externa"</item> + <item msgid="7880769915418638436">"último_toque_barra_estado"</item> + <item msgid="4313165186636015195">"pantalla_enfocada"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 3d5a9bdfedae..536b91816bc4 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Non se puido actualizar o ambiente"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Activo (só contido multimedia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Activo (só contido multimedia). Esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. Dereito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (compatible con audio compartido). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (compatible con audio compartido). Esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de batería. Dereito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (compatible con audio compartido). Esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (compatible con audio compartido). Dereito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de batería."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (compatible con audio compartido)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activo (só contido multimedia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Compatible con audio compartido"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activo (só contido multimedia), só esquerdo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activo (só contido multimedia), só dereito"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activo (só contido multimedia), esquerdo e dereito"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Procesamento acelerado mediante hardware"</string> <string name="media_category" msgid="8122076702526144053">"Multimedia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Supervisión"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Modo estrito activado"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"A pantalla ilumínase se as aplicacións tardan moito no proceso principal"</string> <string name="pointer_location" msgid="7516929526199520173">"Localización do punteiro"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Definir implementación de WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opción xa non é válida. Téntao de novo."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modo de cor da imaxe"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Utiliza sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desactivado"</string> diff --git a/packages/SettingsLib/res/values-gu/arrays.xml b/packages/SettingsLib/res/values-gu/arrays.xml index 6026663ba4df..8d9ef2b05623 100644 --- a/packages/SettingsLib/res/values-gu/arrays.xml +++ b/packages/SettingsLib/res/values-gu/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"માત્ર ડિવાઇસનું ડિસ્પ્લે (ડિફૉલ્ટ)"</item> + <item msgid="9161645858025071955">"બાહ્ય ડિસ્પ્લે"</item> + <item msgid="23651860565814477">"નવીનતમ સ્ટેટસ બાર ટચ"</item> + <item msgid="7521112827893653392">"ફોકસ-આધારિત"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"માત્ર ડિવાઇસના ડિસ્પ્લે પર શેડ બતાવો"</item> + <item msgid="1955398604822147783">"માત્ર એક જ બાહ્ય ડિસ્પ્લે પર શેડ બતાવો"</item> + <item msgid="391477482416751568">"તે ડિસ્પ્લે પર શેડ બતાવો જેની સાથે તેના સ્ટેટસ બારે છેલ્લે ક્રિયાપ્રતિક્રિયા કરી હતી"</item> + <item msgid="1746820128097981528">"છેલ્લે ફોકસ કરેલા ડિસ્પ્લે પર શેડ બતાવો"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 57ecad80e7e9..1b4bad383589 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"આસપાસના અવાજો અપડેટ કરી શક્યા નથી"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"સક્રિય (માત્ર મીડિયા માટે). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"સક્રિય (માત્ર મીડિયા માટે). ડાબી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, જમણી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> બૅટરી."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"કનેક્ટેડ (ઑડિયો શેરિંગને સપોર્ટ કરે છે). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"કનેક્ટેડ (ઑડિયો શેરિંગને સપોર્ટ કરે છે). ડાબી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, જમણી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> બૅટરી."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"કનેક્ટેડ (ઑડિયો શેરિંગને સપોર્ટ કરે છે). ડાબી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"કનેક્ટેડ (ઑડિયો શેરિંગને સપોર્ટ કરે છે). જમણી બાજુ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> બૅટરી."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"કનેક્ટેડ (ઑડિયો શેરિંગને સપોર્ટ કરે છે)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"સક્રિય છે (માત્ર મીડિયા માટે)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ઑડિયો શેરિંગને સપોર્ટ કરે છે"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"સક્રિય છે (માત્ર મીડિયા માટે), માત્ર ડાબી બાજુ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"સક્રિય છે (માત્ર મીડિયા માટે), માત્ર જમણી બાજુ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"સક્રિય છે (માત્ર મીડિયા માટે), ડાબી અને જમણી બાજુ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"હાર્ડવેર પ્રવેગક રેન્ડરિંગ"</string> <string name="media_category" msgid="8122076702526144053">"મીડિયા"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"નિરિક્ષણ કરી રહ્યું છે"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"સ્ટ્રિક્ટ મોડ ચાલુ કરેલો છે"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"જ્યારે મુખ્ય થ્રેડ પર ઍપ લાંબી કામગીરીઓ કરે ત્યારે સ્ક્રીનને ફ્લેશ કરો"</string> <string name="pointer_location" msgid="7516929526199520173">"પૉઇન્ટર લોકેશન"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView અમલીકરણ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView અમલીકરણ સેટ કરો"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"આ વિકલ્પ હવે માન્ય નથી. ફરી પ્રયાસ કરો."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"ચિત્ર રંગ મોડ"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB નો ઉપયોગ કરો"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"બંધ"</string> diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml index 67de2aea289a..9c138d22f8bb 100644 --- a/packages/SettingsLib/res/values-hi/arrays.xml +++ b/packages/SettingsLib/res/values-hi/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"सिर्फ़ डिवाइस का डिसप्ले (डिफ़ॉल्ट)"</item> + <item msgid="9161645858025071955">"बाहरी डिसप्ले पर"</item> + <item msgid="23651860565814477">"हाल ही में स्टेटस बार को टच किया गया"</item> + <item msgid="7521112827893653392">"फ़ोकस के हिसाब से"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"सिर्फ़ डिवाइस के डिसप्ले पर शेड दिखाएं"</item> + <item msgid="1955398604822147783">"किसी एक बाहरी डिसप्ले पर शेड दिखाएं"</item> + <item msgid="391477482416751568">"उस डिसप्ले पर शेड दिखाएं जिसकी स्टेटस बार के साथ पिछली बार इंटरैक्शन किया गया था"</item> + <item msgid="1746820128097981528">"उस डिसप्ले पर शेड दिखाएं जिस पर आखिरी बार फ़ोकस किया गया था"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index c1f4fe25f4aa..55d425fa7b38 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"वॉल्यूम को मैनेज करने की सेटिंग नहीं बदली जा सकी"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"चालू है (सिर्फ़ मीडिया के लिए). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"चालू है (सिर्फ़ मीडिया के लिए). बायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, दायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बैटरी."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"कनेक्ट हो गया (ऑडियो शेयर करने की सुविधा काम करती है). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"कनेक्ट हो गया (ऑडियो शेयर करने की सुविधा काम करती है). बायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, दायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बैटरी."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"कनेक्ट हो गया (ऑडियो शेयर करने की सुविधा काम करती है). बायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"कनेक्ट हो गया (ऑडियो शेयर करने की सुविधा काम करती है). दायां हेडसेट: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बैटरी."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"कनेक्ट है (ऑडियो शेयर करने की सुविधा काम करती है)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"चालू है (सिर्फ़ मीडिया के लिए)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ऑडियो शेयर करने की सुविधा काम करती है"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"चालू है (सिर्फ़ मीडिया के लिए), सिर्फ़ बाएं कान की मशीन"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"चालू है (सिर्फ़ मीडिया के लिए), सिर्फ़ दाएं कान की मशीन"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"चालू है (सिर्फ़ मीडिया के लिए), बाएं और दाएं कान की मशीन"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"हार्डवेयर ऐक्सेलरेटेड रेंडरिंग"</string> <string name="media_category" msgid="8122076702526144053">"मीडिया"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"निगरानी"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"स्ट्रिक्ट मोड चालू रखें"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"थ्रेड पर लंबा प्रोसेस होने पर स्क्रीन फ़्लैश करें"</string> <string name="pointer_location" msgid="7516929526199520173">"पॉइंटर की जगह"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबव्यू लागू करें"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"वेबव्यू सेट करें"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"यह चुनाव अब मान्य नहीं है. दोबारा कोशिश करें."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"चित्र रंग मोड"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB का उपयोग करें"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"बंद"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 131195e42e48..97f2df6a7632 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ažuriranje okruženja nije uspjelo"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktivno (samo medijski sadržaji). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktivno (samo medijski sadržaji), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Povezano (podržava zajedničko slušanje). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Povezano (podržava zajedničko slušanje), L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterije."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Povezano (podržava zajedničko slušanje). Lijeva strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Povezano (podržava zajedničko slušanje). Desna strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Povezano (podržava zajedničko slušanje)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivno (samo medijski sadržaji)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podržava zajedničko slušanje"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivno (samo medijski sadržaji), samo lijeva"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivno (samo medijski sadržaji), samo desna"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivno (samo medijski sadržaji), lijeva i desna"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardverski ubrzano renderiranje"</string> <string name="media_category" msgid="8122076702526144053">"Mediji"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Nadzor"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Omogućen strogi način"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Zaslon bljeska kada operacije aplikacija u glavnoj niti dugo traju"</string> <string name="pointer_location" msgid="7516929526199520173">"Mjesto pokazivača"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacija WebViewa"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Postavi implementaciju WebViewa"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Taj izbor više nije važeći. Pokušajte ponovo."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Način boje slike"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Upotrijebi sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Onemogućeno"</string> diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml index d8d42f952734..677b821fcb69 100644 --- a/packages/SettingsLib/res/values-hu/arrays.xml +++ b/packages/SettingsLib/res/values-hu/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Csak az eszköz kijelzője (alapértelmezett)"</item> + <item msgid="9161645858025071955">"Külső kijelző"</item> + <item msgid="23651860565814477">"Az állapotsor legutóbbi érintése"</item> + <item msgid="7521112827893653392">"Fókusz alapján"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Felület megjelenítése csak az eszköz kijelzőjén"</item> + <item msgid="1955398604822147783">"Felület megjelenítése egyetlen külső kijelzőn"</item> + <item msgid="391477482416751568">"Felület megjelenítése azon a kijelzőn, amelyen utoljára végeztek műveletet az állapotsorral"</item> + <item msgid="1746820128097981528">"Felület megjelenítése az utoljára fókuszban lévő kijelzőn"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index fa321555075f..5e97cff03a79 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Nem sikerült módosítani a környezetet"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktív (csak médiatartalom lejátszása esetén). Akkumulátor töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktív (csak médiatartalom lejátszása esetén). Akkumulátorok töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (bal) és <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (jobb)."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Csatlakoztatva (támogatja a hang megosztását). Akkumulátor töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Csatlakoztatva (támogatja a hang megosztását). Akkumulátorok töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (bal) és <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (jobb)."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Csatlakoztatva (támogatja a hang megosztását). Akkumulátor töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (bal)."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Csatlakoztatva (támogatja a hang megosztását). Akkumulátor töltöttségi szintje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (jobb)."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Csatlakoztatva (támogatja a hang megosztását)."</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktív (csak médiatartalom lejátszása)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Támogatja a hang megosztását"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktív (csak médiatartalom lejátszása), csak a bal"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktív (csak médiatartalom lejátszása), csak a jobb"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktív (csak médiatartalom lejátszása), bal és jobb"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardveres gyorsítású megjelenítés"</string> <string name="media_category" msgid="8122076702526144053">"Média"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Figyelés"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Szigorú mód engedélyezve"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Képernyővillogás a fő szál hosszú műveleteinél"</string> <string name="pointer_location" msgid="7516929526199520173">"Mutató helye"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-megvalósítás"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView-megvalósítás beállítása"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Ez a választás már nem érvényes. Próbálkozzon újra."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Kép színe mód"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB használata"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Letiltva"</string> diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml index b2133fbafb26..f71d1fca0de3 100644 --- a/packages/SettingsLib/res/values-hy/arrays.xml +++ b/packages/SettingsLib/res/values-hy/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Միայն սարքի էկրանը (կանխադրված)"</item> + <item msgid="9161645858025071955">"Արտաքին էկրան"</item> + <item msgid="23651860565814477">"Կարգավիճակի գոտու հետ վերջին փոխազդումը"</item> + <item msgid="7521112827893653392">"Ֆոկուսի հիման վրա"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Ցույց տալ երանգը միայն սարքի էկրանին"</item> + <item msgid="1955398604822147783">"Ցույց տալ երանգը մեկ արտաքին էկրանին"</item> + <item msgid="391477482416751568">"Ցույց տալ երանգն էկրանին, որի կարգավիճակի գոտու հետ վերջերս օգտատերը փոխազդել է"</item> + <item msgid="1746820128097981528">"Ցույց տալ երանգը վերջին ֆոկուսավորված էկրանին"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index fa87813cc122..d3427172c74c 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Չհաջողվեց թարմացնել շրջակայքի կարգավիճակը"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Ակտիվ է (միայն մեդիա)։ Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>։"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Ակտիվ է (միայն մեդիա)։ Ձախ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, աջ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>։"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Միացված է (աջակցում է աուդիոյի փոխանցում)։ Մարտկոցի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>։"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Միացված է (աջակցում է աուդիոյի փոխանցում)։ Ձախ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, աջ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>։"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Միացված է (աջակցում է աուդիոյի փոխանցում)։ Ձախ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>։"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Միացված է (աջակցում է աուդիոյի փոխանցում)։ Աջ ականջակալի լիցքը՝ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>։"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Միացված է (աջակցում է աուդիոյի փոխանցում)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ակտիվ է (միայն մեդիա)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Աջակցում է աուդիոյի փոխանցում"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ակտիվ է (միայն մեդիա), միայն ձախ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ակտիվ է (միայն մեդիա), միայն աջ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ակտիվ է (միայն մեդիա), աջ և ձախ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Սարքաշարի արագացված նյութավորում"</string> <string name="media_category" msgid="8122076702526144053">"Մեդիա"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Մշտադիտարկում"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Խիստ ռեժիմն ակտիվացված է"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Լուսավորել էկրանը` ծրագրի գլխավոր շղթայի վրա երկար աշխատելիս"</string> <string name="pointer_location" msgid="7516929526199520173">"Նշորդի տեղադրությունը"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Ընտրեք WebView-ի իրականացումը"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Այս ընտրանքն այլևս վավեր չէ: Փորձեք նորից:"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Նկարի գունային ռեժիմ"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Օգտագործել sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Կասեցված է"</string> diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml index fa2fa9e3d56c..a4bb2f4a7cdb 100644 --- a/packages/SettingsLib/res/values-in/arrays.xml +++ b/packages/SettingsLib/res/values-in/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Hanya layar perangkat (Default)"</item> + <item msgid="9161645858025071955">"Layar eksternal"</item> + <item msgid="23651860565814477">"Sentuhan status bar terbaru"</item> + <item msgid="7521112827893653392">"Berbasis fokus"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Tampilkan shade hanya di layar perangkat"</item> + <item msgid="1955398604822147783">"Tampilkan menu di satu layar eksternal"</item> + <item msgid="391477482416751568">"Tampilkan menu di layar yang terakhir kali berinteraksi dengan status bar-nya"</item> + <item msgid="1746820128097981528">"Tampilkan menu di layar yang terakhir difokuskan"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 1ff4b29ddaa0..649ee0bb9f47 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Tidak dapat memperbarui suara sekitar"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktif (hanya media). Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktif (hanya media). Baterai L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Terhubung (mendukung berbagi audio). Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Terhubung (mendukung berbagi audio). Baterai L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Terhubung (mendukung berbagi audio). Kiri: Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Terhubung (mendukung berbagi audio). Kanan: Baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Terhubung (mendukung berbagi audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktif (hanya media)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Mendukung berbagi audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktif (hanya media), hanya kiri"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktif (hanya media), hanya kanan"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktif (hanya media), kiri dan kanan"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Render yang dipercepat hardware"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Pemantauan"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Mode ketat diaktifkan"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Buat layar berkedip saat aplikasi berlama-lama menjalankan operasi di thread utama"</string> <string name="pointer_location" msgid="7516929526199520173">"Lokasi kursor"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Penerapan WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Setel penerapan WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Pilihan ini tidak valid lagi. Coba lagi."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Mode warna gambar"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Gunakan sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Dinonaktifkan"</string> @@ -634,7 +662,7 @@ <string name="user_add_profile_item_title" msgid="3111051717414643029">"Profil dibatasi"</string> <string name="user_add_user_title" msgid="5457079143694924885">"Tambahkan pengguna baru?"</string> <string name="user_add_user_message_long" msgid="1527434966294733380">"Anda dapat menggunakan perangkat ini bersama orang lain dengan membuat pengguna tambahan. Setiap pengguna memiliki ruang sendiri, yang dapat disesuaikan dengan aplikasi, wallpaper, dan lainnya. Pengguna juga dapat menyesuaikan setelan perangkat seperti Wi-Fi yang dapat memengaruhi semua pengguna lain.\n\nSaat Anda menambahkan pengguna baru, pengguna tersebut perlu menyiapkan ruangnya.\n\nPengguna mana pun dapat mengupdate aplikasi untuk semua pengguna lainnya. Layanan dan setelan aksesibilitas mungkin tidak ditransfer ke pengguna baru."</string> - <string name="user_add_user_message_short" msgid="3295959985795716166">"Saat Anda menambahkan pengguna baru, orang tersebut harus menyiapkan ruangnya sendiri.\n\nPengguna mana pun dapat meng-update aplikasi untuk semua pengguna lain."</string> + <string name="user_add_user_message_short" msgid="3295959985795716166">"Saat Anda menambahkan pengguna baru, orang tersebut harus menyiapkan ruangnya sendiri.\n\nPengguna mana pun dapat mengupdate aplikasi untuk semua pengguna lain."</string> <string name="user_grant_admin_title" msgid="5157031020083343984">"Jadikan pengguna ini sebagai admin?"</string> <string name="user_grant_admin_message" msgid="1673791931033486709">"Admin memiliki hak istimewa khusus yang tidak dimiliki pengguna lain. Admin dapat mengelola semua pengguna, mengupdate atau mereset perangkat ini, mengubah setelan, melihat semua aplikasi terinstal, dan memberi atau mencabut hak istimewa admin untuk pengguna lain."</string> <string name="user_grant_admin_button" msgid="5441486731331725756">"Jadikan admin"</string> diff --git a/packages/SettingsLib/res/values-is/arrays.xml b/packages/SettingsLib/res/values-is/arrays.xml index 851a7a4929ea..27846cccb13b 100644 --- a/packages/SettingsLib/res/values-is/arrays.xml +++ b/packages/SettingsLib/res/values-is/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Aðeins skjár tækis (sjálfgefið)"</item> + <item msgid="9161645858025071955">"Ytri skjár"</item> + <item msgid="23651860565814477">"Síðasta snerting stöðustiku"</item> + <item msgid="7521112827893653392">"Byggt á fókus"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Aðeins skyggja skjá tækis"</item> + <item msgid="1955398604822147783">"Skyggja stakan ytri skjá"</item> + <item msgid="391477482416751568">"Skyggja skjá þar sem stöðustika var síðast notuð"</item> + <item msgid="1746820128097981528">"Skyggja síðasta skjá í fókus"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index 804ea6318400..d36115729889 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ekki var hægt að uppfæra umhverfi"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Virkt (eingöngu margmiðlunarefni). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Virkt (eingöngu margmiðlunarefni), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> rafhlöðuhleðsla."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Tengt (styður hljóðdeilingu), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Tengt (styður hljóðdeilingu), V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> rafhlöðuhleðsla."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Tengt (styður hljóðdeilingu). Vinstri: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Tengt (styður hljóðdeilingu). Hægri: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> rafhlöðuhleðsla."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Tengt (styður hljóðdeilingu)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Virkt (eingöngu margmiðlunarefni)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Styður hljóðdeilingu"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Virkt (eingöngu margmiðlunarefni), eingöngu vinstri"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Virkt (eingöngu margmiðlunarefni), eingöngu hægri"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Virkt (eingöngu margmiðlunarefni), vinstri og hægri"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Myndþýðing með vélbúnaðarhröðun"</string> <string name="media_category" msgid="8122076702526144053">"Margmiðlun"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Eftirlit"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Kveikt á strangri stillingu"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Blikka skjá ef forrit gera tímafreka hluti á aðalþræði"</string> <string name="pointer_location" msgid="7516929526199520173">"Staðsetning bendils"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Innleiðing WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Stilla innleiðingu WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Þetta val er ekki lengur gilt. Reyndu aftur."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Litastilling mynda"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Nota sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Óvirkt"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 09ec5ccaf23f..98e415b7c6ef 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Impossibile aggiornare audio ambientale"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Attivo (solo contenuti multimediali). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> di batteria."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Attivo (solo contenuti multimediali). S: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> di batteria. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> di batteria."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Connesso (supporta la condivisione audio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> di batteria."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Connesso (supporta la condivisione audio). S: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> di batteria. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> di batteria."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Connesso (supporta la condivisione audio). Sinistro: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> di batteria."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Connesso (supporta la condivisione audio). Destro: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> di batteria."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Connesso (supporta la condivisione audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Attivo (solo contenuti multimediali)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Supporta la condivisione audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Attivo (solo contenuti multimediali), solo sinistro"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Attivo (solo contenuti multimediali), solo destro"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Attivo (solo contenuti multimediali), sinistro e destro"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Rendering con accelerazione hardware"</string> <string name="media_category" msgid="8122076702526144053">"Contenuti multimediali"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoraggio"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Attiva StrictMode"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Fai lampeggiare lo schermo per operazioni lunghe sul thread principale"</string> <string name="pointer_location" msgid="7516929526199520173">"Posizione puntatore"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementazione di WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Imposta l\'implementazione di WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"La selezione non è più valida. Riprova."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modalità colori immagini"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Usa sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Disattivato"</string> diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml index 9d176c03cdfb..744e502eeab0 100644 --- a/packages/SettingsLib/res/values-iw/arrays.xml +++ b/packages/SettingsLib/res/values-iw/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"מסך המכשיר בלבד (ברירת המחדל)"</item> + <item msgid="9161645858025071955">"מסך חיצוני"</item> + <item msgid="23651860565814477">"אינטראקציה אחרונה עם שורת הסטטוס"</item> + <item msgid="7521112827893653392">"לפי התמקדות"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"הצגת הצללה במסך המכשיר בלבד"</item> + <item msgid="1955398604822147783">"הצגת לוח ההתראות במסך חיצוני אחד"</item> + <item msgid="391477482416751568">"הצגת לוח ההתראות במסך שבו הייתה האינטראקציה האחרונה עם שורת הסטטוס"</item> + <item msgid="1746820128097981528">"הצגת לוח ההתראות במסך האחרון שבו המשתמש התמקד"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index 361dd1804e0b..b341c4d199fb 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"לא ניתן לעדכן את עוצמת הרעשים בסביבה"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"פעיל (מדיה בלבד). סוללה: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"פעיל (מדיה בלבד). סוללה בצד שמאל: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, סוללה בצד ימין: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"מחובר (תמיכה בשיתוף אודיו). סוללה: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"מחובר (תמיכה בשיתוף אודיו). סוללה בצד שמאל: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, סוללה בצד ימין: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"מחובר (תמיכה בשיתוף אודיו). סוללה בצד שמאל: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"מחובר (תמיכה בשיתוף אודיו). סוללה בצד ימין: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"מחובר (תמיכה בשיתוף אודיו)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"פעיל (מדיה בלבד)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"תמיכה בשיתוף אודיו"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"פעיל (מדיה בלבד), שמאל בלבד"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"פעיל (מדיה בלבד), ימין בלבד"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"פעיל (מדיה בלבד), שמאל וימין"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"עיבוד מואץ של חומרה"</string> <string name="media_category" msgid="8122076702526144053">"מדיה"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"מעקב"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"מצב קפדני מופעל"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"המסך יהבהב כשאפליקציות יבצעו פעולות ארוכות ב-thread הראשי"</string> <string name="pointer_location" msgid="7516929526199520173">"מיקום מצביע"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"יישום WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"הגדרת יישום WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"אפשרות זו כבר אינה תקפה. אפשר לנסות שוב."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"מצב צבע התמונה"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"שימוש ב-sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"מושבת"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index 1170cd1db76a..2e36d6a3d291 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"周囲の音を更新できませんでした"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"有効(メディアのみ)。バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"有効(メディアのみ)。左: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>、右: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"接続済み(音声の共有をサポート)。バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"接続済み(音声の共有をサポート)。左: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>、右: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"接続済み(音声の共有をサポート)。左: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"接続済み(音声の共有をサポート)。右: バッテリー残量 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"接続済み(音声の共有をサポート)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"有効(メディアのみ)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"音声の共有をサポートしています"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"有効(メディアのみ)、左のみ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"有効(メディアのみ)、右のみ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"有効(メディアのみ)、左右"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ハードウェアアクセラレーテッドレンダリング"</string> <string name="media_category" msgid="8122076702526144053">"メディア"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"モニタリング"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"厳格モードを有効にする"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"メインスレッドの処理が長引く場合は画面を点滅させる"</string> <string name="pointer_location" msgid="7516929526199520173">"ポインタの位置"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView の実装"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView の実装の設定"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"この選択は無効になりました。もう一度お試しください。"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"画像の色モード"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGBを使用"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"無効"</string> diff --git a/packages/SettingsLib/res/values-ka/arrays.xml b/packages/SettingsLib/res/values-ka/arrays.xml index 8ee333835a06..3ecf9d86e2b3 100644 --- a/packages/SettingsLib/res/values-ka/arrays.xml +++ b/packages/SettingsLib/res/values-ka/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"მხოლოდ მოწყობილობის ეკრანი (ნაგულისხმევი)"</item> + <item msgid="9161645858025071955">"გარე ეკრანი"</item> + <item msgid="23651860565814477">"სტატუსის ზოლის ბოლო შეხება"</item> + <item msgid="7521112827893653392">"ფოკუსის მიხედვით"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"ჩრდილის ჩვენება მხოლოდ მოწყობილობის ეკრანზე"</item> + <item msgid="1955398604822147783">"ჩრდილის ჩვენება ერთ გარე ეკრანზე"</item> + <item msgid="391477482416751568">"ეკრანზე ჩრდილის ჩვენება, რომლის სტატუსის ზოლთანაც მოხდა ბოლო ინტერაქცია"</item> + <item msgid="1746820128097981528">"ჩრდილის ჩვენება ბოლო ფოკუსირებულ ეკრანზე"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"ფოკუსირებული_ეკრანი"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 6503795b3634..e627b794d9a5 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"გარემოცვის განახლება ვერ მოხერხდა"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"აქტიური (მხოლოდ მედია). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>%% ბატარეა."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"აქტიური (მხოლოდ მედია), მარცხენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, მარჯვენა:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ბატარეა."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია). ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია). მარცხენა: ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, მარჯვენა: ბატარეა <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია). მარცხენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ბატარეა."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია). მარჯვენა: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ბატარეა."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"დაკავშირებული (აუდიოს გაზიარება მხარდაჭერილია)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"აქტიური (მხოლოდ მედია)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"აუდიოს გაზიარება მხარდაჭერილია"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"აქტიური (მხოლოდ მედია), მხოლოდ მარცხენა"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"აქტიური (მხოლოდ მედია), მხოლოდ მარჯვენა"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"აქტიური (მხოლოდ მედია), მარცხენა და მარჯვენა"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"აპარატურით დაჩქარებული გამოსახულება"</string> <string name="media_category" msgid="8122076702526144053">"მედია"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"მონიტორინგი"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"მკაცრი რეჟიმი ჩართულია"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"ეკრანის აციმციმება, როცა აპები ახორციელებენ ხანგრძლივ ოპერაციებს მთავარ ნაკადზე"</string> <string name="pointer_location" msgid="7516929526199520173">"მაჩვენებლის მდებარეობა"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView რეალიზაცია"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView რეალიზაციის დაყენება"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"თქვენი არჩევანი აღარ მოქმედებს. ცადეთ ხელახლა."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"გამოსახულების ფერების რეჟიმი"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB-ს გამოყენება"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"გამორთულია"</string> diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml index 6aa5f2b1c4e5..e2510a703736 100644 --- a/packages/SettingsLib/res/values-kk/arrays.xml +++ b/packages/SettingsLib/res/values-kk/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Тек құрылғы дисплейі (әдепкі)"</item> + <item msgid="9161645858025071955">"Сыртқы дисплей"</item> + <item msgid="23651860565814477">"Соңғы күй жолағын түрту"</item> + <item msgid="7521112827893653392">"Назарға негізделген"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Құрылғы дисплейінде ғана реңк көрсету"</item> + <item msgid="1955398604822147783">"Жалғыз сыртқы дисплейде көлеңкені көрсету"</item> + <item msgid="391477482416751568">"Күй жолағы соңғы рет қолданылған дисплейде көлеңкені көрсету"</item> + <item msgid="1746820128097981528">"Соңғы рет назарда болған дисплейде көлеңкені көрсету"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 9082a5665f92..a85e6245fa60 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Айналаны жаңарту мүмкін болмады."</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Істеп тұр (тек мультимедиа). Батарея зарядының деңгейі – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Істеп тұр (тек мультимедиа). Сол жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. Оң жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Жалғанып тұр (аудио бөлісу мүмкіндігі бар). Батарея зарядының деңгейі – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Қосылды (аудио бөлісуге мүмкіндік береді). Сол жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>. Оң жақ: батарея зарядының деңгейі — <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Қосылды (аудио бөлісуге мүмкіндік береді). Сол жақ: батарея зарядының деңгейі – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Қосылды (аудио бөлісуге мүмкіндік береді). Оң жақ: батарея зарядының деңгейі – <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Жалғанды (аудио бөлісу мүмкіндігі бар)."</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Істеп тұр (тек мультимедиа)."</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Аудио бөлісуге мүмкіндік береді."</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Тек сол жақ істеп тұр (мультимедиа ғана)."</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Тек оң жақ істеп тұр (мультимедиа ғана)."</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Сол және оң жақ істеп тұр (мультимедиа ғана)."</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Бейнелеуді аппаратпен жеделдету"</string> <string name="media_category" msgid="8122076702526144053">"Mультимeдиа"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Бақылау"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Қатаң режим қосылған"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Қолданбалар ұзақ операцияларды орындағанда экранды жыпылықтату"</string> <string name="pointer_location" msgid="7516929526199520173">"Меңзер орны"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView қызметі"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView ендіруін орнату"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Бұл таңдау енді жарамды емес. Әрекетті қайталаңыз."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Сурет түс режимі"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB пайдалану"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Өшірулі"</string> diff --git a/packages/SettingsLib/res/values-km/arrays.xml b/packages/SettingsLib/res/values-km/arrays.xml index e9a21e87312f..07e64a5ed50f 100644 --- a/packages/SettingsLib/res/values-km/arrays.xml +++ b/packages/SettingsLib/res/values-km/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"ផ្ទាំងអេក្រង់ឧបករណ៍តែប៉ុណ្ណោះ (លំនាំដើម)"</item> + <item msgid="9161645858025071955">"ផ្ទាំងអេក្រង់ខាងក្រៅ"</item> + <item msgid="23651860565814477">"ការចុចរបារស្ថានភាពចុងក្រោយបំផុត"</item> + <item msgid="7521112827893653392">"ផ្អែកលើការផ្ដោត"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"បង្ហាញផ្ទាំងនៅលើផ្ទាំងអេក្រង់ឧបករណ៍តែប៉ុណ្ណោះ"</item> + <item msgid="1955398604822147783">"បង្ហាញផ្ទាំងនៅលើផ្ទាំងអេក្រង់ខាងក្រៅតែមួយ"</item> + <item msgid="391477482416751568">"បង្ហាញផ្ទាំងនៅលើផ្ទាំងអេក្រង់ដែលមានការធ្វើអន្តរកម្មចុងក្រោយលើរបារស្ថានភាពរបស់វា"</item> + <item msgid="1746820128097981528">"បង្ហាញផ្ទាំងនៅលើផ្ទាំងអេក្រង់ដែលបានផ្ដោតចុងក្រោយ"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 3cc214e91f9a..d2d5893c969b 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"មិនអាចប្ដូរមជ្ឈដ្ឋានជុំវិញបានទេ"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ)។ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>។"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ)។ ឆ្វេង៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ស្ដាំ៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>។"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា)។ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>។"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា)។ ឆ្វេង៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ស្ដាំ៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>។"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា)។ ឆ្វេង៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>។"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា)។ ស្ដាំ៖ ថ្ម <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>។"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"បានភ្ជាប់ (អាចប្រើការស្ដាប់សំឡេងរួមគ្នា)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"អាចប្រើការស្ដាប់សំឡេងរួមគ្នា"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ) តែខាងឆ្វេងប៉ុណ្ណោះ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ) តែខាងស្ដាំប៉ុណ្ណោះ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"សកម្ម (តែមេឌៀប៉ុណ្ណោះ) ឆ្វេង និងស្ដាំ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ការបំប្លែងដែលពន្លឿនដោយប្រើហាតវែរ"</string> <string name="media_category" msgid="8122076702526144053">"មេឌៀ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"តាមដាន"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"បានបើកមុខងារតឹងរ៉ឹង"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"បញ្ចេញពន្លឺអេក្រង់ពេលកម្មវិធីធ្វើប្រតិបត្តិការយូរលើសែស្រឡាយមេ"</string> <string name="pointer_location" msgid="7516929526199520173">"ទីតាំងទ្រនិច"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"ការអនុវត្ត WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"កំណត់ការប្រតិបត្តិ WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ជម្រើសនេះលែងមានសុពលភាពទៀតហើយ ព្យាយាមម្តងទៀត"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"របៀបនៃពណ៌រូបភាព"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"ប្រើ sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"បានបិទ"</string> diff --git a/packages/SettingsLib/res/values-kn/arrays.xml b/packages/SettingsLib/res/values-kn/arrays.xml index dc9c7e096ab3..de2269aa54c9 100644 --- a/packages/SettingsLib/res/values-kn/arrays.xml +++ b/packages/SettingsLib/res/values-kn/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"ಸಾಧನದ ಡಿಸ್ಪ್ಲೇ ಮಾತ್ರ (ಡೀಫಾಲ್ಟ್)"</item> + <item msgid="9161645858025071955">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇ"</item> + <item msgid="23651860565814477">"ಇತ್ತೀಚಿನ ಸ್ಥಿತಿ ಪಟ್ಟಿಯ ಸ್ಪರ್ಶ"</item> + <item msgid="7521112827893653392">"ಫೋಕಸ್-ಆಧಾರಿತ"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"ಸಾಧನದ ಡಿಸ್ಪ್ಲೇನಲ್ಲಿ ಮಾತ್ರ ಶೇಡ್ ತೋರಿಸಿ"</item> + <item msgid="1955398604822147783">"ಒಂದೇ ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇನಲ್ಲಿ ಶೇಡ್ ಅನ್ನು ತೋರಿಸಿ"</item> + <item msgid="391477482416751568">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಕೊನೆಯದಾಗಿ ಸಂವಹನ ನಡೆಸಿದ ಶೇಡ್ ಅನ್ನು ಡಿಸ್ಪ್ಲೇ ಮೇಲೆ ತೋರಿಸಿ"</item> + <item msgid="1746820128097981528">"ಕೊನೆಯ ಕೇಂದ್ರೀಕೃತ ಡಿಸ್ಪ್ಲೇನಲ್ಲಿ ಶೇಡ್ ಅನ್ನು ತೋರಿಸಿ"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index d2b217683d41..87f2cdf9e340 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"ಆ್ಯಂಬಿಯೆಂಟ್ ಸ್ಥಿತಿಯನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ). ಎಡ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ಬಲ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ). ಎಡ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ಬಲ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ). ಎಡ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ). ಬಲ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ಬ್ಯಾಟರಿ ಮಟ್ಟ."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"ಕನೆಕ್ಟ್ ಆಗಿದೆ (ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ಆಡಿಯೋ ಹಂಚಿಕೊಳ್ಳುವಿಕೆಯನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ), ಎಡ ಭಾಗದ ಮಾತ್ರ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ), ಬಲ ಭಾಗದ ಮಾತ್ರ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ಸಕ್ರಿಯವಾಗಿದೆ (ಮೀಡಿಯಾ ಮಾತ್ರ), ಎಡ ಮತ್ತು ಬಲ ಭಾಗದ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ಹಾರ್ಡ್ವೇರ್ ವೇಗವರ್ಧಿತ ರೆಂಡರಿಂಗ್"</string> <string name="media_category" msgid="8122076702526144053">"ಮಾಧ್ಯಮ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"ಪರಿವೀಕ್ಷಣೆ ಮಾಡುವಿಕೆ"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"ಸ್ಟ್ರಿಕ್ಟ್ ಮೋಡ್ ಸಕ್ರಿಯ"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮುಖ್ಯ ಥ್ರೆಡ್ನಲ್ಲಿ ದೀರ್ಘ ಕಾರ್ಯಾಚರಣೆ ನಿರ್ವಹಿಸಿದಾಗ ಪರದೆಯನ್ನು ಫ್ಲ್ಯಾಶ್ ಮಾಡು"</string> <string name="pointer_location" msgid="7516929526199520173">"ಪಾಯಿಂಟರ್ ಸ್ಥಳ"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ಸೆಟ್ ಮಾಡಿ"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ಈ ಆಯ್ಕೆಯು ಇನ್ನು ಮುಂದೆ ಮಾನ್ಯವಾಗಿರುವುದಿಲ್ಲ. ಮತ್ತೊಮ್ಮೆ ಪ್ರಯತ್ನಿಸಿ."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"ಚಿತ್ರ ಬಣ್ಣದ ಮೋಡ್"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ಬಳಸಿ"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml index 1477497197c0..3cc5af02efd2 100644 --- a/packages/SettingsLib/res/values-ko/arrays.xml +++ b/packages/SettingsLib/res/values-ko/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"기기 디스플레이만(기본값)"</item> + <item msgid="9161645858025071955">"외부 디스플레이"</item> + <item msgid="23651860565814477">"최근 상태 표시줄 터치"</item> + <item msgid="7521112827893653392">"포커스 기반"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"기기 디스플레이에만 음영 표시"</item> + <item msgid="1955398604822147783">"단일 외부 디스플레이에 음영 표시"</item> + <item msgid="391477482416751568">"마지막으로 상호작용한 상태 표시줄이 있는 디스플레이에 음영 표시"</item> + <item msgid="1746820128097981528">"마지막으로 포커스된 디스플레이에 음영 표시"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index bece63792ecb..669d8ef89655 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"주변 소리를 업데이트할 수 없음"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"사용 중입니다(미디어 전용). 배터리는 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>입니다."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"사용 중입니다(미디어 전용). 배터리는 왼쪽 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, 오른쪽 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>입니다."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"연결되었습니다(오디오 공유 지원). 배터리는 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>입니다."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"연결되었습니다(오디오 공유 지원). 배터리는 왼쪽 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, 오른쪽 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>입니다."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"연결되었습니다(오디오 공유 지원). 왼쪽 배터리는 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>입니다."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"연결되었습니다(오디오 공유 지원). 오른쪽 배터리는 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>입니다."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"연결됨(오디오 공유 지원)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"사용 중(미디어 전용)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"오디오 공유 지원"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"사용 중(미디어 전용), 왼쪽만"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"사용 중(미디어 전용), 오른쪽만"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"사용 중(미디어 전용), 왼쪽 및 오른쪽"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"하드웨어 가속 렌더링"</string> <string name="media_category" msgid="8122076702526144053">"미디어"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"모니터링"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"엄격 모드 사용"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"앱이 기본 스레드에서 오래 작업하면 화면 깜박이기"</string> <string name="pointer_location" msgid="7516929526199520173">"포인터 위치"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 구현"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView 구현 설정"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"선택이 더 이상 유효하지 않습니다. 다시 시도하세요."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"사진 색상 모드"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB 사용"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"사용 중지됨"</string> diff --git a/packages/SettingsLib/res/values-ky/arrays.xml b/packages/SettingsLib/res/values-ky/arrays.xml index 54d9ecd5fbae..5e4044351c4b 100644 --- a/packages/SettingsLib/res/values-ky/arrays.xml +++ b/packages/SettingsLib/res/values-ky/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Түзмөктүн экраны гана (демейки)"</item> + <item msgid="9161645858025071955">"Тышкы экран"</item> + <item msgid="23651860565814477">"Абал тилкесине акыркы жолу тийүү"</item> + <item msgid="7521112827893653392">"Акыркы аракетке негизделген"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Көлөкөнү түзмөктүн экранында гана көрсөтүү"</item> + <item msgid="1955398604822147783">"Көлөкөнү бир тышкы экранда көрсөтүү"</item> + <item msgid="391477482416751568">"Көлөкөнү колдонуучу абал тилкеси менен акыркы жолу аракеттешкен экранда көрсөтүү"</item> + <item msgid="1746820128097981528">"Көлөкөнү акыркы активдүү экранда көрсөтүү"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index b6baf38df4d3..c69325b2dc43 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Айланадагы абал жаңыртылган жок"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Жигердүү (медиа үчүн гана). Батарея: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Жигердүү (медиа үчүн гана). Батарея: L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Туташып турат (чогуу уксаңыз болот). Батарея: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Туташып турат (чогуу уксаңыз болот). Батарея: L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Туташып турат (чогуу уксаңыз болот). Сол кулак – батареянын деңгээли: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Туташып турат (чогуу уксаңыз болот). Оң кулак – батареянын деңгээли: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Туташып турат (чогуу уксаңыз болот)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активдүү (медиа үчүн гана)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Чогуу уксаңыз болот"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активдүү (медиа үчүн гана), сол кулакчын гана"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активдүү (медиа үчүн гана), оң кулакчын гана"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активдүү (медиа үчүн гана), сол жана оң кулакчын"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Визуалдаштырууну аппарат менен ылдамдатуу"</string> <string name="media_category" msgid="8122076702526144053">"Медиа"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Мониторинг"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Катаал режим иштетилди"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Узак операцияларда экран күйүп-өчүп турат"</string> <string name="pointer_location" msgid="7516929526199520173">"Көрсөткүчтүн турган жери"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView кызматы"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView аткарылышын коюу"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Тандалган нерсе жараксыз болуп калган. Кайталап көрүңүз."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Сүрөт түсү режими"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB колдонуңуз"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Өчүк"</string> diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml index ccf645b2d77c..cf0a7834b690 100644 --- a/packages/SettingsLib/res/values-lo/arrays.xml +++ b/packages/SettingsLib/res/values-lo/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"ຈໍສະແດງຜົນຂອງອຸປະກອນເທົ່ານັ້ນ (ຄ່າເລີ່ມຕົ້ນ)"</item> + <item msgid="9161645858025071955">"ຈໍສະແດງຜົນພາຍນອກ"</item> + <item msgid="23651860565814477">"ການສຳຜັດແຖບສະຖານະຫຼ້າສຸດ"</item> + <item msgid="7521112827893653392">"ອີງຕາມການໂຟກັສ"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"ສະແດງເສດສີໃນຈໍສະແດງຜົນຂອງອຸປະກອນເທົ່ານັ້ນ"</item> + <item msgid="1955398604822147783">"ສະແດງເສດສີໃນຈໍສະແດງຜົນພາຍນອກເຄື່ອງດຽວ"</item> + <item msgid="391477482416751568">"ສະແດງເສດສີໃນຈໍສະແດງຜົນທີ່ມີການໂຕ້ຕອບກັບແຖບສະຖານະຫຼ້າສຸດ"</item> + <item msgid="1746820128097981528">"ສະແດງເສດສີໃນຈໍສະແດງຜົນທີ່ໂຟກັສຫຼ້າສຸດ"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 3046b4fab03e..d1f1344fd506 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"ບໍ່ສາມາດອັບເດດສຽງແວດລ້ອມໄດ້"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ). ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ). ຊ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ຂ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ). ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ). ຊ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ຂ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ). ຊ້າຍ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ). ຂວາ: ແບັດເຕີຣີ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"ເຊື່ອມຕໍ່ແລ້ວ (ຮອງຮັບການແບ່ງປັນສຽງ)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ຮອງຮັບການແບ່ງປັນສຽງ"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຊ້າຍເທົ່ານັ້ນ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຂວາເທົ່ານັ້ນ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ນຳໃຊ້ຢູ່ (ມີເດຍເທົ່ານັ້ນ), ຊ້າຍ ແລະ ຂວາ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ການສະແດງຜົນໂດຍໃຊ້ຮາດແວຊ່ວຍ"</string> <string name="media_category" msgid="8122076702526144053">"ມີເດຍ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"ກຳລັງກວດສອບ"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"ເປີດໃຊ້ໂໝດເຄັ່ງຄັດ"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"ກະພິບໜ້າຈໍເມື່ອມີແອັບເຮັດວຽກດົນເກີນໄປໃນເທຣດຫຼັກ"</string> <string name="pointer_location" msgid="7516929526199520173">"ຕຳແໜ່ງໂຕຊີ້"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"ຕັ້ງການຈັດຕັ້ງປະຕິບັດ WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ບໍ່ສາມາດໃຊ້ການເລືອກນີ້ໄດ້ອີກຕໍ່ໄປແລ້ວ. ກະລຸນາລອງໃໝ່."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"ໂໝດສີຮູບ"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"ໃຊ້ sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"ປິດນຳໃຊ້ແລ້ວ"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index f81caa830ddd..7f940109e867 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Nepavyko atnaujinti aplinkos"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktyvus (tik medija). Akumuliatorius lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktyvus (tik medija), akumuliatoriaus lygis kairėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, dešinėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Prijungta (palaikomas garso įrašų bendrinimas). Akumuliatoriaus lygis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Prijungta (palaikomas garso įrašų bendrinimas), akumuliatoriaus lygis kairėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, dešinėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Prijungta (palaikomas garso įrašų bendrinimas). Akumuliatoriaus lygis kairėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Prijungta (palaikomas garso įrašų bendrinimas). Akumuliatoriaus lygis dešinėje: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Prijungta (palaikomas garso įrašų bendrinimas)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktyvus (tik medija)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Palaikomas garso įrašų bendrinimas"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktyvus (tik medija), tik kairė"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktyvus (tik medija), tik dešinė"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktyvus (tik medija), kairė ir dešinė"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Aparatinės įrangos paspartintas pateikimas"</string> <string name="media_category" msgid="8122076702526144053">"Medija"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Stebėjimas"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Įgal. griežtas režimas"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Ekr. blyksės, kai pr. atl. ilgus proc. pgr. gijoje"</string> <string name="pointer_location" msgid="7516929526199520173">"Žymiklio vieta"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"„WebView“ diegimas"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"„WebView“ diegimo nustatymas"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Šios parinkties nebegalima pasirinkti. Bandykite dar kartą."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Nuotraukos spalvos režimas"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Naudoti sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Išjungtas"</string> diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml index 6d293be28a4e..da4ae31f7c82 100644 --- a/packages/SettingsLib/res/values-lv/arrays.xml +++ b/packages/SettingsLib/res/values-lv/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Tikai ierīces displejs (noklusējums)"</item> + <item msgid="9161645858025071955">"Ārējais displejs"</item> + <item msgid="23651860565814477">"Pēdējais pieskāriens statusa joslai"</item> + <item msgid="7521112827893653392">"Saskaņā ar fokusu"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Rādīt ēnu tikai ierīces displejā"</item> + <item msgid="1955398604822147783">"Rādīt ēnu vienā ārējā displejā"</item> + <item msgid="391477482416751568">"Rādīt ēnu tajā displejā, kura statusa joslā pēdējoreiz tika veikta darbība"</item> + <item msgid="1746820128097981528">"Rādīt ēnu pēdējā fokusētajā displejā"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index 987857b9a6bd..50a56d4c956f 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Nevarēja atjaunināt apkārtnes skaņas"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktīvs (tikai multividei). Akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktīvs (tikai multividei). Akumulatora uzlādes līmenis kreisajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, labajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Izveidots savienojums (atbalsta audio kopīgošanu). Akumulatora uzlādes līmenis: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Izveidots savienojums (atbalsta audio kopīgošanu). Akumulatora uzlādes līmenis kreisajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, labajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Izveidots savienojums (atbalsta audio kopīgošanu). Akumulatora uzlādes līmenis kreisajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Izveidots savienojums (atbalsta audio kopīgošanu). Akumulatora uzlādes līmenis labajā austiņā: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Izveidots savienojums (atbalsta audio kopīgošanu)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktīvs (tikai multividei)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Atbalsta audio kopīgošanu"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktīvs (tikai multivide), tikai kreisās puses aparāts"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktīvs (tikai multivide), tikai labās puses aparāts"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktīvs (tikai multivide), kreisās un labās puses aparāts"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Aparatūras paātrinātā atveidošana"</string> <string name="media_category" msgid="8122076702526144053">"Multivide"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Pārraudzība"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Precīzais rež. ir iespēj."</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Zibsnīt ekrānu, ja liet. ilgi darbojas galv. pav."</string> <string name="pointer_location" msgid="7516929526199520173">"Rādītāja atrašanās vieta"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ieviešana"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Iestatīt WebView ieviešanu"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Šī iespēja vairs nav derīga. Mēģiniet vēlreiz."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Attēla krāsu režīms"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Izmantot sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Atspējota"</string> diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml index 0490f2822c5f..4dce6bc5d9d0 100644 --- a/packages/SettingsLib/res/values-mk/arrays.xml +++ b/packages/SettingsLib/res/values-mk/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Само на екранот на уредот (стандардно)"</item> + <item msgid="9161645858025071955">"Надворешен екран"</item> + <item msgid="23651860565814477">"Последен допир на статусната лента"</item> + <item msgid="7521112827893653392">"Засновано на фокус"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Прикажувај сенка само на екранот на уредот"</item> + <item msgid="1955398604822147783">"Прикажувај сенка на еден надворешен екран"</item> + <item msgid="391477482416751568">"Прикажувај сенка на екранот што последен имал интеракција со статусната лента"</item> + <item msgid="1746820128097981528">"Прикажувај сенка на последниот фокусиран екран"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"стандарден_екран"</item> + <item msgid="774789415968826925">"кој_било_надворешен_екран"</item> + <item msgid="7880769915418638436">"последен_допир_на_статусната_лента"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index fa654379f7ee..e86a6cee6249 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Не можеше да се ажурира опкружувањето"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Активно (само аудиовизуелни содржини). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Активно (само аудиовизуелни содржини). Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерија, Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерија."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Поврзано (поддржува споделување аудио). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Поврзано (поддржува споделување аудио). Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерија, Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерија."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Поврзано (поддржува споделување аудио). Лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Поврзано (поддржува споделување аудио). Десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Поврзано (поддржува споделување аудио)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активно (само аудиовизуелни содржини)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Поддржува споделување аудио"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активно (само аудиовизуелни содржини), само лево"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активно (само аудиовизуелни содржини), само десно"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активно (само аудиовизуелни содржини), лево и десно"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Хардверско забрзување"</string> <string name="media_category" msgid="8122076702526144053">"Аудиовизуелни содржини"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Следење"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Овозможен е строг режим"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Трепкај со екранот при долги операции на главна нишка"</string> <string name="pointer_location" msgid="7516929526199520173">"Локација на покажувач"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Примена на WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Поставете воведување WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Овој избор веќе не важи. Обидете се повторно."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Режим на боја на слика"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Користи sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Оневозможено"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 3e59d9f0b586..f7ab232ff0fe 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"സറൗണ്ടിംഗ്സ് അപ്ഡേറ്റ് ചെയ്യാനായില്ല"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"സജീവം (മീഡിയ മാത്രം). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"സജീവം (മീഡിയ മാത്രം). ഇടതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ബാറ്ററി, വലതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ബാറ്ററി."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു). ഇടതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> ബാറ്ററി, വലതുവശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ബാറ്ററി."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു). ഇടത് വശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു). വലത് വശത്ത്: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ബാറ്ററി."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"കണക്റ്റ് ചെയ്തു (ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു)."</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"സജീവം (മീഡിയ മാത്രം)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ഓഡിയോ പങ്കിടൽ പിന്തുണയ്ക്കുന്നു"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"സജീവം (മീഡിയ മാത്രം), ഇടതുവശത്ത് മാത്രം"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"സജീവം (മീഡിയ മാത്രം), വലതുവശത്ത് മാത്രം"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"സജീവം (മീഡിയ മാത്രം), ഇടതുവശത്തെയും വലതുവശത്തെയും"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ഹാർഡ്വെയർ ത്വരിതപ്പെടുത്തിയ റെൻഡറിംഗ്"</string> <string name="media_category" msgid="8122076702526144053">"മീഡിയ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"മോണിറ്ററിംഗ്"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"ഫോഴ്സ്മോഡ് സജീവമാക്കി"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"പ്രധാന ത്രെഡിൽ ആപ്പുകൾ ദൈർഘ്യമേറിയ പ്രവർത്തനങ്ങൾ നടത്തുമ്പോൾ സ്ക്രീൻ ഫ്ലാഷ് ചെയ്യുക"</string> <string name="pointer_location" msgid="7516929526199520173">"പോയിന്റർ ലൊക്കേഷൻ"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView നടപ്പാക്കൽ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView നടപ്പാക്കൽ സജ്ജമാക്കുക"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ഈ തിരഞ്ഞെടുപ്പിന് തുടർന്നങ്ങോട്ട് സാധുതയില്ല. വീണ്ടും ശ്രമിക്കുക."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"ചിത്ര വർണ്ണ മോഡ്"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ഉപയോഗിക്കുക"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"പ്രവർത്തനരഹിതമാക്കി"</string> diff --git a/packages/SettingsLib/res/values-mn/arrays.xml b/packages/SettingsLib/res/values-mn/arrays.xml index ca103afc9bbc..121371dc85c2 100644 --- a/packages/SettingsLib/res/values-mn/arrays.xml +++ b/packages/SettingsLib/res/values-mn/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Зөвхөн төхөөрөмжийн дэлгэц (өгөгдмөл)"</item> + <item msgid="9161645858025071955">"Гаднын дэлгэц"</item> + <item msgid="23651860565814477">"Статус самбарын сүүлийн үеийн хүрэлт"</item> + <item msgid="7521112827893653392">"Төвлөрөлд тулгуурласан"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Зөвхөн төхөөрөмж дээрх дэлгэцэд сүүдрийг харуулах"</item> + <item msgid="1955398604822147783">"Нэг гаднын дэлгэц дээр сүүдэр харуулах"</item> + <item msgid="391477482416751568">"Статус самбартай нь сүүлд харилцан үйлдэл хийсэн дэлгэц дээр сүүдэр харуулах"</item> + <item msgid="1746820128097981528">"Сүүлд төвлөрсөн дэлгэц дээр сүүдэр харуулах"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index e8e9e0caf08a..4dc754e9f378 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Орчин тойрныг шинэчилж чадсангүй"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Идэвхтэй (зөвхөн медиа). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Идэвхтэй (зөвхөн медиа). З: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Б: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарей."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Холбогдсон (аудио хуваалцахыг дэмждэг). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Холбогдсон (аудио хуваалцахыг дэмждэг). З: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Б: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарей."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Холбогдсон (аудио хуваалцахыг дэмждэг). Зүүн: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Холбогдсон (аудио хуваалцахыг дэмждэг). Баруун: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Холбогдсон (аудио хуваалцахыг дэмждэг)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Идэвхтэй (зөвхөн медиа)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Аудио хуваалцахыг дэмждэг"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Идэвхтэй (зөвхөн медиа), зөвхөн зүүн"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Идэвхтэй (зөвхөн медиа), зөвхөн баруун"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Идэвхтэй (зөвхөн медиа), зүүн болон баруун"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Техник хангамжийн хурдасгасан үзүүлэлт"</string> <string name="media_category" msgid="8122076702526144053">"Медиа"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Мониторинг"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Хатуу горимыг идэвхжүүлсэн"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Аппууд үндсэн хэлхээс дээр удаан хугацаанд үйлдлүүд хийх үед дэлгэцийг анивчуулах"</string> <string name="pointer_location" msgid="7516929526199520173">"Чиглүүлэгчийн байршил"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView хэрэгжилт"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView хэрэгжилтийг тохируулах"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Энэ сонголт хүчингүй байна. Дахин оролдоно уу."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"\"Зургийн өнгө\" горим"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB-г ашиглах"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Идэвхгүй болсон"</string> diff --git a/packages/SettingsLib/res/values-mr/arrays.xml b/packages/SettingsLib/res/values-mr/arrays.xml index 1437a2cd8660..eba95aeea014 100644 --- a/packages/SettingsLib/res/values-mr/arrays.xml +++ b/packages/SettingsLib/res/values-mr/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"फक्त डिव्हाइस डिस्प्ले (डीफॉल्ट)"</item> + <item msgid="9161645858025071955">"बाह्य डिस्प्ले"</item> + <item msgid="23651860565814477">"नवीनतम स्टेटस बार स्पर्श"</item> + <item msgid="7521112827893653392">"फोकसवर आधारित"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"फक्त डिव्हाइस डिस्प्लेवर शेड दाखवा"</item> + <item msgid="1955398604822147783">"एकल बाह्य डिस्प्लेवर शेड दाखवा"</item> + <item msgid="391477482416751568">"त्याच्या स्टेटस बारशी शेवटचा संवाद साधला आहे अशा डिस्प्लेवर शेड दाखवा"</item> + <item msgid="1746820128097981528">"शेवटच्या फोकस केलेल्या डिस्प्लेवर शेड दाखवा"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index f1f5cab8d6a7..eef39c433d32 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"जवळपासचे आवाज अपडेट करता आले नाहीत"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"अॅक्टिव्ह आहे (फक्त मीडिया). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"ॲक्टिव्ह आहे (फक्त मीडिया). डावीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> बॅटरी, उजवीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बॅटरी."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते). डावीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, उजवीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> बॅटरी."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते). डावीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते). उजवीकडे: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> बॅटरी."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"कनेक्ट केले आहे (ऑडिओ शेअरिंगला सपोर्ट करते)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"अॅक्टिव्ह आहे (फक्त मीडिया)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ऑडिओ शेअरिंगला सपोर्ट करते"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"अॅक्टिव्ह आहे (फक्त मीडिया), फक्त डावे"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"अॅक्टिव्ह आहे (फक्त मीडिया), फक्त उजवे"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"अॅक्टिव्ह आहे (फक्त मीडिया), डावे आणि उजवे"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"हार्डवेअर अॅक्सिलरेटेड रेंडरिंग"</string> <string name="media_category" msgid="8122076702526144053">"मीडिया"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"परीक्षण"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"कठोर मोड सुरू"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"मुख्य थ्रेडवर अॅप्स मोठी कार्ये करतात तेव्हा स्क्रीन फ्लॅश करा"</string> <string name="pointer_location" msgid="7516929526199520173">"पॉइंटर स्थान"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"वेबदृश्य अंमलबजावणी सेट करा"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ही निवड यापुढे वैध असणार नाही. पुन्हा प्रयत्न करा."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"चित्र रंग मोड"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB वापरा"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"बंद केले"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 412100c07009..ca4649ccd888 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Tidak dapat mengemaskinikan persekitaran"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktif (media sahaja). Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktif (media sahaja), L: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Disambungkan (menyokong perkongsian audio). Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Disambungkan (menyokong perkongsian audio). L: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Disambungkan (menyokong perkongsian audio). Kiri: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Disambungkan (menyokong perkongsian audio). Kanan: Bateri <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Disambungkan (menyokong perkongsian audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktif (media sahaja)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Menyokong perkongsian audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktif (media sahaja), kiri sahaja"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktif (media sahaja), kanan sahaja"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktif (media sahaja), kiri dan kanan"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Pemaparan dipercepat perkakasan"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Memantau"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Mod tegas didayakan"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Kelip skrin apabila apl beroperasi lama pada urutan utama"</string> <string name="pointer_location" msgid="7516929526199520173">"Lokasi penuding"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Pelaksanaan WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Tetapkan pelaksanaan WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Pilihan ini tidak lagi sah. Cuba lagi."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Mod warna gambar"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Gunakan sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Dilumpuhkan"</string> diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml index aef22b2203de..91ce12a600a1 100644 --- a/packages/SettingsLib/res/values-my/arrays.xml +++ b/packages/SettingsLib/res/values-my/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"စက်ဖန်သားပြင် သီးသန့် (မူရင်း)"</item> + <item msgid="9161645858025071955">"ပြင်ပဖန်သားပြင်"</item> + <item msgid="23651860565814477">"နောက်ဆုံး အခြေအနေပြဘား တို့ထိမှု"</item> + <item msgid="7521112827893653392">"ပြသမှုအခြေပြု"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"စက်ဖန်သားပြင်တွင်သာ အရိပ်ပြပါ"</item> + <item msgid="1955398604822147783">"ပြင်ပဖန်သားပြင်တစ်ခုတွင် အရိပ်ကိုပြပါ"</item> + <item msgid="391477482416751568">"အခြေအနေပြဘား နောက်ဆုံးပြန်လှန်တုံ့ပြန်ထားသော ဖန်သားပြင်တွင် အရိပ်ကိုပြပါ"</item> + <item msgid="1746820128097981528">"နောက်ဆုံးပြထားသော ဖန်သားပြင်တွင် အရိပ်ကိုပြပါ"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"မူရင်းဖန်သားပြင်"</item> + <item msgid="774789415968826925">"မည်သည့်ပြင်ပဖန်သားပြင်မဆို"</item> + <item msgid="7880769915418638436">"အခြေအနေပြဘား နောက်ဆုံးထိတွေ့မှု"</item> + <item msgid="4313165186636015195">"ပြသထားသောဖန်သားပြင်"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index cf493cf40a9c..1225e4c3e8a3 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"ဝန်းကျင်အသံ အပ်ဒိတ်လုပ်၍ မရလိုက်ပါ"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"အသုံးပြုနေသည် (မီဒီယာသီးသန့်)။ ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>။"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"အသုံးပြုနေသည် (မီဒီယာသီးသန့်)။ ဘက်ထရီ L- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>၊ R- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>။"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)။ ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>။"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)။ ဘက်ထရီ L- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>၊ R- <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>။"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)။ ဘယ်- ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>။"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)။ ညာ- ဘက်ထရီ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>။"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"ချိတ်ဆက်ထားသည် (အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"သုံးနေသည် (မီဒီယာသီးသန့်)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"အော်ဒီယို မျှဝေခြင်း ပံ့ပိုးသည်"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"သုံးနေသည် (မီဒီယာသီးသန့်)၊ ဘယ်သီးသန့်"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"သုံးနေသည် (မီဒီယာသီးသန့်)၊ ညာသီးသန့်"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"သုံးနေသည် (မီဒီယာသီးသန့်)၊ ဘယ်နှင့် ညာ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ဟာ့ဒ်ဝဲ အရှိန်မြှင့် ပုံဖော်ခြင်း"</string> <string name="media_category" msgid="8122076702526144053">"မီဒီယာ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"စောင့်ကြည့်စစ်ဆေးခြင်း"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"တင်းကြပ်သောစနစ် ဖွင့်ရန်"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"အက်ပ်လုပ်ဆောင်မှု ရှည်ကြာလျှင် စကရင်ပြန်စသည်"</string> <string name="pointer_location" msgid="7516929526199520173">"မြား၏တည်နေရာ"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView အကောင်အထည်ဖော်မှု"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView အကောင်အထည်ဖော်မှု သတ်မှတ်ပါ"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ဤရွေးချယ်မှု မှန်ကန်မှု မရှိတော့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"ဓာတ်ပုံအရောင်မုဒ်"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ကို အသုံးပြုပါ"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"ပိတ်ထားသည်"</string> diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml index 88f193c119fc..c0106c46b74e 100644 --- a/packages/SettingsLib/res/values-nb/arrays.xml +++ b/packages/SettingsLib/res/values-nb/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Bare enhetsskjermen (standard)"</item> + <item msgid="9161645858025071955">"Ekstern skjerm"</item> + <item msgid="23651860565814477">"Siste trykk på statusfeltet"</item> + <item msgid="7521112827893653392">"Fokusbasert"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Vis skyggen bare på enhetsskjermen"</item> + <item msgid="1955398604822147783">"Vis skyggen på én ekstern skjerm"</item> + <item msgid="391477482416751568">"Vis skyggen på skjermen hvor det ble trykket på statusfeltet sist"</item> + <item msgid="1746820128097981528">"Vis skyggen på den sist fokuserte skjermen"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"Standardskjerm"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 045318a765b7..7c9b10f00267 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Kunne ikke oppdatere omgivelsene"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktiv (bare medieinnhold) <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiv (bare medieinnhold). V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Tilkoblet (støtter lyddeling). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Tilkoblet (støtter lyddeling). V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batteri, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Tilkoblet (støtter lyddeling). Venstre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Tilkoblet (støtter lyddeling). Høyre: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Tilkoblet (støtter lyddeling)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (bare medieinnhold)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Støtter lyddeling"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (bare medieinnhold), bare venstre"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (bare medieinnhold), bare høyre"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (bare medieinnhold), høyre og venstre"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Maskinvareakselerert gjengivelse"</string> <string name="media_category" msgid="8122076702526144053">"Medier"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Overvåking"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Slå på streng modus"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Skjermblink ved lange apphandlinger på hovedtråd"</string> <string name="pointer_location" msgid="7516929526199520173">"Pekerplassering"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Angi WebView-implementering"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Dette valget er ikke gyldig lenger. Prøv på nytt."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Fargemodus for bilder"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Bruk sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Slått av"</string> diff --git a/packages/SettingsLib/res/values-ne/arrays.xml b/packages/SettingsLib/res/values-ne/arrays.xml index 1989994a289c..23d634371426 100644 --- a/packages/SettingsLib/res/values-ne/arrays.xml +++ b/packages/SettingsLib/res/values-ne/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"२"</item> <item msgid="4779928470672877922">"३"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"डिभाइसको डिस्प्ले मात्र (डिफल्ट)"</item> + <item msgid="9161645858025071955">"बाह्य डिस्प्ले"</item> + <item msgid="23651860565814477">"पछिल्लो पटक स्ट्याटस बारमा टच गरिएको"</item> + <item msgid="7521112827893653392">"फोकसमा आधारित"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"यो सेड डिभाइसकै डिस्प्लेमा मात्र देखाउनुहोस्"</item> + <item msgid="1955398604822147783">"एउटा बाह्य डिस्प्लेमा सेड देखाउनुहोस्"</item> + <item msgid="391477482416751568">"पछिल्लो पटक जुन डिस्प्लेको स्ट्याटस बारमा टच गरिएको थियो सो डिस्प्लेमा सेड देखाउनुहोस्"</item> + <item msgid="1746820128097981528">"पछिल्लो पटक फोकस गरिएको डिस्प्लेमा सेड देखाउनुहोस्"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index d637a4bb9640..e2e7a8f48c76 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"वरपरका आवाजसम्बन्धी सेटिङ अपडेट गर्न सकिएन"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"सक्रिय छ (मिडिया मात्र)। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ब्याट्री।"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"सक्रिय छ (मिडिया मात्र)। बायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, दायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ब्याट्री।"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ)। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ब्याट्री।"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ)। बायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, दायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ब्याट्री।"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ)। बायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ब्याट्री।"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ)। दायाँ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ब्याट्री।"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"कनेक्ट गरिएको छ (अडियो सेयर गर्न मिल्छ)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"सक्रिय छ (मिडिया मात्र)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"अडियो सेयर गर्न मिल्छ"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"सक्रिय छ (मिडिया मात्र), बायाँ मात्र"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"सक्रिय छ (मिडिया मात्र), दायाँ मात्र"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"सक्रिय छ (मिडिया मात्र), बायाँ र दायाँ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"हार्डवेयरले बढाएको रेन्डरिङ"</string> <string name="media_category" msgid="8122076702526144053">"मिडिया"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"अनुगमन गरिँदै छ"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"स्ट्रिक्ट मोड अन गर्नुहोस्"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"एपले मुख्य थ्रेडमा लामा गतिविधि गर्दा स्क्रिन फ्ल्यास गर्नुहोस्"</string> <string name="pointer_location" msgid="7516929526199520173">"पोइन्टरको स्थान"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView कार्यान्वयन सेट गर्नुहोस्"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"यो छनोट अब मान्य छैन। फेरि प्रयास गर्नुहोस्।"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"चित्र रङ्ग मोड"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB प्रयोग गर्नुहोस्"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"अफ गरिएको छ"</string> @@ -657,8 +685,8 @@ <string name="add_guest_failed" msgid="8074548434469843443">"नयाँ अतिथि बनाउन सकिएन"</string> <string name="user_nickname" msgid="262624187455825083">"उपनाम"</string> <string name="edit_user_info_message" msgid="6677556031419002895">"यो डिभाइस प्रयोग गर्ने सबै जना तपाईंले छनौट गर्ने नाम र फोटो देख्न सक्ने छन्।"</string> - <string name="user_add_user" msgid="7876449291500212468">"प्रयोगकर्ता कनेक्ट गर्नुहोस्"</string> - <string name="guest_new_guest" msgid="3482026122932643557">"अतिथि कनेक्ट गर्नुहोस्"</string> + <string name="user_add_user" msgid="7876449291500212468">"प्रयोगकर्ता थप्नुहोस्"</string> + <string name="guest_new_guest" msgid="3482026122932643557">"अतिथि थप्नुहोस्"</string> <string name="guest_exit_guest" msgid="5908239569510734136">"अथिति हटाउनुहोस्"</string> <string name="guest_reset_guest" msgid="6110013010356013758">"अतिथि सत्र रिसेट गर्नुहोस्"</string> <string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"अतिथिका रूपमा ब्राउज गर्ने सेसन रिसेट गर्ने हो?"</string> diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml index 12c9551d850f..669326ae1f70 100644 --- a/packages/SettingsLib/res/values-nl/arrays.xml +++ b/packages/SettingsLib/res/values-nl/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Alleen apparaatscherm (standaard)"</item> + <item msgid="9161645858025071955">"Extern scherm"</item> + <item msgid="23651860565814477">"Laatste aanraking van statusbalk"</item> + <item msgid="7521112827893653392">"Op focus gebaseerd"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Alleen paneel tonen op apparaatscherm"</item> + <item msgid="1955398604822147783">"Venster tonen op één extern scherm"</item> + <item msgid="391477482416751568">"Venster tonen op scherm waarop de laatst interactie met de statusbalk was"</item> + <item msgid="1746820128097981528">"Venster tonen op laatste gefocuste scherm"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 481479e21f74..6dfcc7b0b40c 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Kan omgeving niet updaten"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Actief (alleen media). Batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Actief (alleen media), L: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Verbonden (ondersteunt audio delen), batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Verbonden (ondersteunt audio delen), L: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Verbonden (ondersteunt audio delen). Links: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Verbonden (ondersteunt audio delen). Rechts: batterijniveau <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Verbonden (ondersteunt audio delen)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Actief (alleen media)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Ondersteunt audio delen"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Actief (alleen media), alleen links"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Actief (alleen media), alleen rechts"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Actief (alleen media), links en rechts"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Rendering met hardwareversnelling"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Controle"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strikte modus staat aan"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Knipperend scherm bij lange bewerkingen door apps"</string> <string name="pointer_location" msgid="7516929526199520173">"Cursorlocatie"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementatie"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView-implementatie instellen"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Deze keuze is niet meer geldig. Probeer het opnieuw."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Kleurenmodus voor afbeeldingen"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB gebruiken"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Uitgezet"</string> diff --git a/packages/SettingsLib/res/values-or/arrays.xml b/packages/SettingsLib/res/values-or/arrays.xml index 97823036d96a..3b906c4a175b 100644 --- a/packages/SettingsLib/res/values-or/arrays.xml +++ b/packages/SettingsLib/res/values-or/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"କେବଳ ଡିଭାଇସ ଡିସପ୍ଲେ (ଡିଫଲ୍ଟ)"</item> + <item msgid="9161645858025071955">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେ"</item> + <item msgid="23651860565814477">"ନବୀନତମ ଷ୍ଟାଟସ ବାର ଟଚ"</item> + <item msgid="7521112827893653392">"ଫୋକସ-ଆଧାରିତ"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"କେବଳ ଡିଭାଇସରେ ଡିସପ୍ଲେ ସେଡ ଦେଖାନ୍ତୁ"</item> + <item msgid="1955398604822147783">"ସିଙ୍ଗଲ ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେରେ ସେଡ ଦେଖାନ୍ତୁ"</item> + <item msgid="391477482416751568">"ଡିସପ୍ଲେରେ ଏପରି ସେଡ ଦେଖାନ୍ତୁ ଯାହା ସହିତ ଏହାର ଷ୍ଟାଟସ ବାର ଶେଷ ଥର ପାଇଁ ଇଣ୍ଟରାକ୍ଟ ହୋଇଛି"</item> + <item msgid="1746820128097981528">"ଫୋକସ କରାଯାଇଥିବା ଗତ ଡିସପ୍ଲେରେ ସେଡ ଦେଖାନ୍ତୁ"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index bcde4e9bb831..44c819cbb9b8 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"ପରିପାର୍ଶ୍ୱକୁ ଅପଡେଟ କରାଯାଇପାରିଲା ନାହିଁ"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ)। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ।"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ)। ବାମ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ଡାହାଣ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ବେଟେରୀ।"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"କନେକ୍ଟ କରାଯାଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସପୋର୍ଟ କରେ)। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ।"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"କନେକ୍ଟ କରାଯାଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସମର୍ଥନ କରେ)। ବାମ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ଡାହାଣ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ବେଟେରୀ।"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"କନେକ୍ଟ କରାଯାଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସମର୍ଥନ କରେ)। ବାମ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ।"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"କନେକ୍ଟ କରାଯାଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସପୋର୍ଟ କରେ)। ଡାହାଣ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ବେଟେରୀ।"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"କନେକ୍ଟ କରାଯାଇଛି (ଅଡିଓ ସେୟାରିଂକୁ ସମର୍ଥନ କରେ)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ଅଡିଓ ସେୟାରିଂକୁ ସପୋର୍ଟ କରେ"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), କେବଳ ବାମ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), କେବଳ ଡାହାଣ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ସକ୍ରିୟ (କେବଳ ମିଡିଆ), ବାମ ଏବଂ ଡାହାଣ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ହାର୍ଡୱେର୍ ଆକ୍ସଲରେଟେଡ୍ ରେଣ୍ଡରିଙ୍ଗ"</string> <string name="media_category" msgid="8122076702526144053">"ମିଡିଆ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"ମନିଟରିଙ୍ଗ"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"କଡ଼ା ମୋଡ୍ ସକ୍ଷମ କରାଯାଇଛି"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"ମୁଖ୍ୟ ଥ୍ରେଡ୍ରେ ଆପ୍ ଦୀର୍ଘ ସମୟ କାର୍ଯ୍ୟ କଲେ ସ୍କ୍ରୀନ୍ ଫ୍ଲାଶ୍ କରନ୍ତୁ"</string> <string name="pointer_location" msgid="7516929526199520173">"ପଏଣ୍ଟର୍ ଲୋକେସନ୍"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"ୱେବ୍ଭ୍ୟୁ ପ୍ରୟୋଗ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView କାର୍ଯ୍ୟକାରିତାକୁ ସେଟ୍ କରନ୍ତୁ"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ଏହି ପସନ୍ଦ ଆଉ ମାନ୍ୟ ନାହିଁ। ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"ପିକ୍ଚର୍ ରଙ୍ଗ ମୋଡ୍"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"ଅକ୍ଷମ ହୋଇଛି"</string> diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml index afb85cae2d1e..115214f41e3f 100644 --- a/packages/SettingsLib/res/values-pa/arrays.xml +++ b/packages/SettingsLib/res/values-pa/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"ਸਿਰਫ਼ ਡੀਵਾਈਸ ਦੀ ਡਿਸਪਲੇ (ਪੂਰਵ-ਨਿਰਧਾਰਿਤ)"</item> + <item msgid="9161645858025071955">"ਬਾਹਰੀ ਡਿਸਪਲੇ"</item> + <item msgid="23651860565814477">"ਨਵੀਨਤਮ ਸਥਿਤੀ ਪੱਟੀ ਸਪਰਸ਼"</item> + <item msgid="7521112827893653392">"ਫੋਕਸ-ਆਧਾਰਿਤ"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"ਸਿਰਫ਼ ਡੀਵਾਈਸ ਦੀ ਡਿਸਪਲੇ \'ਤੇ ਸ਼ੇਡ ਦਿਖਾਓ"</item> + <item msgid="1955398604822147783">"ਇਕਹਿਰੇ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਸ਼ੇਡ ਦਿਖਾਓ"</item> + <item msgid="391477482416751568">"ਉਸ ਡਿਸਪਲੇ \'ਤੇ ਸ਼ੇਡ ਦਿਖਾਓ ਜਿਸ ਦੀ ਸਥਿਤੀ ਪੱਟੀ ਨਾਲ ਅਖੀਰ ਵਾਰ ਅੰਤਰਕਿਰਿਆ ਕੀਤੀ ਗਈ ਸੀ"</item> + <item msgid="1746820128097981528">"ਆਖਰੀ ਵਾਰ ਫੋਕਸ ਕੀਤੇ ਗਏ ਡਿਸਪਲੇ \'ਤੇ ਸ਼ੇਡ ਦਿਖਾਓ"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 821c84e20901..731c195065af 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"ਆਲੇ-ਦੁਆਲੇ ਨੂੰ ਅੱਪਡੇਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ)। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ।"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ)। ਖੱਬੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ਸੱਜੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ਬੈਟਰੀ।"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ)। <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ।"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ)। ਖੱਬੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ਸੱਜੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ਬੈਟਰੀ।"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ)। ਖੱਬੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ।"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ)। ਸੱਜੇ ਪਾਸੇ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ਬੈਟਰੀ।"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"ਕਨੈਕਟ ਕੀਤਾ (ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ਆਡੀਓ ਸਾਂਝਾਕਰਨ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ), ਸਿਰਫ਼ ਖੱਬਾ"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ), ਸਿਰਫ਼ ਸੱਜਾ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ਕਿਰਿਆਸ਼ੀਲ (ਸਿਰਫ਼ ਮੀਡੀਆ), ਖੱਬਾ ਅਤੇ ਸੱਜਾ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ਹਾਰਡਵੇਅਰ ਐਕਸੈੱਲਰੇਟਿਡ ਰੈਂਡਰਿੰਗ"</string> <string name="media_category" msgid="8122076702526144053">"ਮੀਡੀਆ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"ਨਿਰੀਖਣ ਕਰਨਾ"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"ਸਟ੍ਰਿਕਟ ਮੋਡ ਚਾਲੂ ਹੈ"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"ਐਪਾਂ ਵੱਲੋਂ ਮੁੱਖ ਥ੍ਰੈੱਡ \'ਤੇ ਲੰਬੀਆਂ ਕਾਰਵਾਈਆਂ ਕਰਨ \'ਤੇ ਸਕ੍ਰੀਨ ਫਲੈਸ਼ ਕਰੋ"</string> <string name="pointer_location" msgid="7516929526199520173">"ਪੁਆਇੰਟਰ ਟਿਕਾਣਾ"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲੀਕਰਨ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView ਅਮਲੀਕਰਨ ਸੈੱਟ ਕਰੋ"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ਇਹ ਚੋਣ ਹੁਣ ਵੈਧ ਨਹੀਂ ਹੈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"ਤਸਵੀਰ ਰੰਗ ਮੋਡ"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ਵਰਤੋਂ ਕਰੋ"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"ਬੰਦ ਹੈ"</string> diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml index 59791c0e70b6..6daf1b2569f8 100644 --- a/packages/SettingsLib/res/values-pl/arrays.xml +++ b/packages/SettingsLib/res/values-pl/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Tylko wyświetlanie na urządzeniu (domyślnie)"</item> + <item msgid="9161645858025071955">"Wyświetlacz zewnętrzny"</item> + <item msgid="23651860565814477">"Ostatnie dotknięcie paska stanu"</item> + <item msgid="7521112827893653392">"Na podstawie aktywnego wyświetlacza"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Pokaż cień tylko na wyświetlaczu urządzenia"</item> + <item msgid="1955398604822147783">"Pokazuj cień na pojedynczym wyświetlaczu zewnętrznym"</item> + <item msgid="391477482416751568">"Pokazuj cień na wyświetlaczu, na którym ostatnio nastąpiła interakcja z paskiem stanu"</item> + <item msgid="1746820128097981528">"Pokazuj cień na ostatnim aktywnym wyświetlaczu"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 9f6eb4c6a7c7..b9adae26df7e 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Nie udało się zaktualizować otoczenia"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktywne (tylko multimedia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktywne (tylko multimedia), lewa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, prawa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> naładowania baterii."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Połączone (obsługa udostępniania dźwięku), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Połączone (obsługa udostępniania dźwięku), lewa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, prawa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> naładowania baterii."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Połączone (obsługa udostępniania dźwięku). Lewa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Połączone (obsługa udostępniania dźwięku). Prawa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> naładowania baterii."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Połączone (obsługa udostępniania dźwięku)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktywne (tylko multimedia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Obsługa udostępniania dźwięku"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktywne (tylko multimedia), tylko lewa"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktywne (tylko multimedia), tylko prawa"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktywne (tylko multimedia), lewa i prawa"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Sprzętowa akceleracja renderowania"</string> <string name="media_category" msgid="8122076702526144053">"Multimedia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitorowanie"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Tryb ścisły włączony"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Miganie ekranu podczas długich operacji w wątku głównym"</string> <string name="pointer_location" msgid="7516929526199520173">"Lokalizacja wskaźnika"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacja WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Ustaw implementację WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Ta opcja nie jest już obsługiwana. Spróbuj ponownie."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Tryb kolorów obrazu"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Użyj sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Wyłączone"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 72f25be8e66f..5b3bb0600eb9 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Não foi possível atualizar o som ambiente"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Ativo (apenas mídia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Ativo (apenas mídia). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (aceita compartilhamento de áudio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (aceita compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (aceita compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (aceita compartilhamento de áudio). Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (aceita compartilhamento de áudio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ativo (apenas mídia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Com suporte ao compartilhamento de áudio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas mídia), apenas esquerdo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ativo (apenas mídia), somente direito"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ativo (apenas mídia), esquerdo e direito"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Renderização acelerada por hardware"</string> <string name="media_category" msgid="8122076702526144053">"Mídia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoramento"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Modo restrito ativado"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Piscar tela se apps demorarem no processo principal"</string> <string name="pointer_location" msgid="7516929526199520173">"Localização do cursor"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Configurar implementação do WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opção não é mais válida. Tente novamente."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modo de cor da imagem"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Usar sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desativado"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index d09caadb6328..e6b343ab9457 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Não foi possível atualizar o ambiente"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Ativo (apenas para multimédia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Ativo (apenas para multimédia). E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Ligado (suporta partilha de áudio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Ligado (suporta partilha de áudio). E: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Ligado (suporta a partilha de áudio). Esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Ligado (suporta a partilha de áudio). Direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Ligado (suporta a partilha de áudio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ativo (apenas para multimédia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Suporta partilha de áudio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas para multimédia), apenas esquerdo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ativo (apenas para multimédia), apenas direito"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ativo (apenas para multimédia), esquerdo e direito"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Conversão acelerada de hardware"</string> <string name="media_category" msgid="8122076702526144053">"Multimédia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitorização"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Modo rigoroso ativado"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Piscar ecrã se app fazem oper. prolong. no tópico princ."</string> <string name="pointer_location" msgid="7516929526199520173">"Localização do ponteiro"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Definir implementação WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opção já não é válida. Tente novamente."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modo de cor da imagem"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Usar sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desativado"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 72f25be8e66f..5b3bb0600eb9 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Não foi possível atualizar o som ambiente"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Ativo (apenas mídia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Ativo (apenas mídia). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (aceita compartilhamento de áudio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (aceita compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (aceita compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (aceita compartilhamento de áudio). Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (aceita compartilhamento de áudio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ativo (apenas mídia)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Com suporte ao compartilhamento de áudio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas mídia), apenas esquerdo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Ativo (apenas mídia), somente direito"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Ativo (apenas mídia), esquerdo e direito"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Renderização acelerada por hardware"</string> <string name="media_category" msgid="8122076702526144053">"Mídia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoramento"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Modo restrito ativado"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Piscar tela se apps demorarem no processo principal"</string> <string name="pointer_location" msgid="7516929526199520173">"Localização do cursor"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Configurar implementação do WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Esta opção não é mais válida. Tente novamente."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modo de cor da imagem"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Usar sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Desativado"</string> diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml index 8bfeb70d0fe4..edaf788b82de 100644 --- a/packages/SettingsLib/res/values-ro/arrays.xml +++ b/packages/SettingsLib/res/values-ro/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Numai pe ecranul dispozitivului (prestabilit)"</item> + <item msgid="9161645858025071955">"Ecran extern"</item> + <item msgid="23651860565814477">"Cea mai recentă atingere a barei de stare"</item> + <item msgid="7521112827893653392">"În funcție de focalizare"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Afișează umbra doar pe ecranul dispozitivului"</item> + <item msgid="1955398604822147783">"Afișează umbra pe un singur ecran extern"</item> + <item msgid="391477482416751568">"Afișează umbra pe ecranul pe care s-a interacționat ultima dată cu bara de stare"</item> + <item msgid="1746820128097981528">"Afișează umbra pe ultimul ecran focalizat"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 26fdce813a04..13c9032603ca 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Nu s-a putut actualiza zona din jur"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Activ (numai pentru conținut media). Nivelul bateriei <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Activ (numai pentru conținut media): nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, nivelul bateriei din dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectat (acceptă permiterea accesului la audio). Nivelul bateriei: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectat (acceptă permiterea accesului la audio), nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, nivelul bateriei din dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectat (acceptă permiterea accesului la audio). Nivelul bateriei din stânga: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectat (acceptă permiterea accesului la audio). Nivelul bateriei din dreapta: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectat (acceptă permiterea accesului la audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Activ (numai pentru conținut media)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Acceptă permiterea accesului la audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Activ (numai pentru conținut media), numai stânga"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Activ (numai pentru conținut media), numai dreapta"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Activ (numai pentru conținut media), stânga și dreapta"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Redare accelerată hardware"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitorizare"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Modul Strict activat"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Iluminare intermitentă la operații lungi pe firul principal"</string> <string name="pointer_location" msgid="7516929526199520173">"Locația indicatorului"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementare WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Setează implementarea WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Această opțiune nu mai este validă. Încearcă din nou."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modul de culori pentru imagini"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Folosește sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Dezactivat"</string> diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml index 52b2549dd60e..a31168ef76a3 100644 --- a/packages/SettingsLib/res/values-ru/arrays.xml +++ b/packages/SettingsLib/res/values-ru/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Только экран устройства (по умолчанию)"</item> + <item msgid="9161645858025071955">"Внешний дисплей"</item> + <item msgid="23651860565814477">"Последнее нажатие на строку состояния"</item> + <item msgid="7521112827893653392">"Последняя активность"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Показывать тень только на экране устройства"</item> + <item msgid="1955398604822147783">"Показывать панель уведомлений на единственном внешнем дисплее"</item> + <item msgid="391477482416751568">"Показывать панель уведомлений на дисплее, со строкой состояния которого пользователь взаимодействовал в последний раз"</item> + <item msgid="1746820128097981528">"Показывать панель уведомлений на дисплее, на который пользователь перешел в последний раз"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index bf92e20fe4d7..831623d6c80b 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Не удалось отрегулировать окружающие звуки."</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Используется (только для медиа), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Используется (только для медиа), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (Л), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (П)."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Подключено (поддерживается отправка аудио), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Подключено (поддерживается отправка аудио), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (Л), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (П)."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Подключено (поддерживается отправка аудио), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (Л)."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Подключено (поддерживается отправка аудио), заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (П)."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Подключено (поддерживается отправка аудио)."</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Используется (только для медиа)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Поддерживается отправка аудио"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Используется (только для медиа), только левый"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Используется (только для медиа), правый наушник"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Используется (только для медиа), левый и правый наушники"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Аппаратное ускорение отрисовки"</string> <string name="media_category" msgid="8122076702526144053">"Мультимедиа"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Мониторинг"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Строгий режим"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Подсвечивать экран во время длительных операций"</string> <string name="pointer_location" msgid="7516929526199520173">"Место касания"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Сервис WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Настройки сервиса WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Вариант недействителен. Повторите попытку."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Цветовой режим"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Использовать sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Отключено"</string> diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml index 66f1ba757a68..f9e9ae14f729 100644 --- a/packages/SettingsLib/res/values-si/arrays.xml +++ b/packages/SettingsLib/res/values-si/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"උපාංග සංදර්ශකය පමණි (පෙරනිමි)"</item> + <item msgid="9161645858025071955">"බාහිර සංදර්ශකය"</item> + <item msgid="23651860565814477">"නවතම තත්ත්ව තීරු ස්පර්ශය"</item> + <item msgid="7521112827893653392">"නාභිගත කිරීම-පාදක"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"උපාංග සංදර්ශකයේ පමණක් සෙවන පෙන්වන්න"</item> + <item msgid="1955398604822147783">"තනි බාහිර සංදර්ශකය මත වැස්ම පෙන්වන්න"</item> + <item msgid="391477482416751568">"තත්ත්ව තීරුව අවසන් වරට අන්තර්ක්රියා කළ වැස්ම දර්ශනයේ පෙන්වන්න."</item> + <item msgid="1746820128097981528">"අවසන් වරට නාභිගත කළ සංදර්ශකයේ වැස්ම පෙන්වන්න"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"නාභිගත කළ_සංදර්ශකය"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index 94e1ed429de6..dcfb914b6c86 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"වටපිටාව යාවත්කාලීන කළ නොහැකි විය"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"ක්රියාත්මකයි (මාධ්ය පමණයි). බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"ක්රියාත්මකයි (මාධ්ය පමණයි), බැටරිය ව: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ද: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීමට සහය දක්වයි). බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීමට සහය දක්වයි). බැටරිය ව: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ද: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීමට සහය දක්වයි). වම: බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීමට සහය දක්වයි). දකුණ: බැටරිය <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"සම්බන්ධයි (ශ්රව්ය බෙදා ගැනීමට සහය දක්වයි)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"සක්රිය (මාධ්ය පමණි)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ශ්රව්ය බෙදා ගැනීම සහය දක්වයි"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"සක්රිය (මාධ්ය පමණි), වම පමණි"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"සක්රිය (මාධ්ය පමණි), දකුණ පමණි"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"සක්රිය (මාධ්ය පමණි), වම සහ දකුණ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"දෘඩාංග වේගය වැඩි කළ පිරිනැමීම"</string> <string name="media_category" msgid="8122076702526144053">"මාධ්ය"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"නිරීක්ෂණය"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"තදබල ආකාරය සබල කිරීම"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"මූලික පොටේ යෙදුම්, දිගු මෙහෙයුම් කරන විට තිරය ෆ්ලෑෂ් කරන්න"</string> <string name="pointer_location" msgid="7516929526199520173">"සූචක පිහිටීම"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ක්රියාත්මක කිරීම"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView ක්රියාත්මක කිරීම සකසන්න"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"මෙම තෝරා ගැනීම තව දුරටත් වලංගු නැත. නැවත උත්සාහ කරන්න."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"පින්තූර වර්ණ ප්රකාරය"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB භාවිතා කරන්න"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"අබලයි"</string> diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml index f8363cdfc447..2d39d3a407ec 100644 --- a/packages/SettingsLib/res/values-sk/arrays.xml +++ b/packages/SettingsLib/res/values-sk/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Iba obrazovka zariadenia (predvolené)"</item> + <item msgid="9161645858025071955">"Externá obrazovka"</item> + <item msgid="23651860565814477">"Posledné klepnutie na stavový riadok"</item> + <item msgid="7521112827893653392">"Na základe označenia"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Zobraziť panel iba na obrazovke zariadenia"</item> + <item msgid="1955398604822147783">"Zobraziť panel na jednej externej obrazovke"</item> + <item msgid="391477482416751568">"Zobraziť panel na obrazovke, na ktorej došlo naposledy k interakcii so stavovým riadkom"</item> + <item msgid="1746820128097981528">"Zobraziť panel na poslednej označenej obrazovke"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 6170ac53255e..86e827438e79 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Okolie sa nepodarilo aktualizovať"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktívne (iba médiá). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktívne (iba médiá). Ľ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> batérie, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batérie."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Pripojené (podporuje zdieľanie zvuku). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Pripojené (podporuje zdieľanie zvuku). Ľ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, P: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batérie."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Pripojené (podporuje zdieľanie zvuku). Ľavá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Pripojené (podporuje zdieľanie zvuku). Pravá strana: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batérie."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Pripojené (podporuje zdieľanie zvuku)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktívne (iba médiá)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podporuje zdieľanie zvuku"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktívne (iba médiá), iba ľavá strana"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktívne (iba médiá), iba pravá strana"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktívne (iba médiá), ľavá aj pravá strana"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hardvérom zrýchlené vykresľovanie"</string> <string name="media_category" msgid="8122076702526144053">"Médiá"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitorovanie"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Povoliť prísny režim"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Blikať pri dlhých operáciách hlavného vlákna"</string> <string name="pointer_location" msgid="7516929526199520173">"Umiestnenie kurzora"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementácia WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Nastaviť implementáciu WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Táto voľba už nie je platná. Skúste to znova."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Farebný režim obrázka"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Použije sa sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Vypnuté"</string> diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml index 2a128efde3bc..498224a2d948 100644 --- a/packages/SettingsLib/res/values-sl/arrays.xml +++ b/packages/SettingsLib/res/values-sl/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Prikaz samo v napravi (privzeto)"</item> + <item msgid="9161645858025071955">"Zunanji zaslon"</item> + <item msgid="23651860565814477">"Zadnji dotik vrstice stanja"</item> + <item msgid="7521112827893653392">"Na podlagi fokusa"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Prikaz podokna samo na zaslonu naprave"</item> + <item msgid="1955398604822147783">"Prikaz podokna na enem zunanjem zaslonu"</item> + <item msgid="391477482416751568">"Prikaz podokna na zaslonu, na katerem je bila izvedena zadnja interakcija z vrstico stanja"</item> + <item msgid="1746820128097981528">"Prikaz podokna na zadnjem zaslonu s fokusom"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 39b61d9c331f..28ae8e14472d 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Okolice ni bilo mogoče posodobiti"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktivno (samo predstavnost). Baterija: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktivno (samo predstavnost), baterija – L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Povezano (podpira deljenje zvoka), baterija: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Povezano (podpira deljenje zvoka), baterija – L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, D: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Povezano (podpira deljenje zvoka). Levo – baterija: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Povezano (podpira deljenje zvoka). Desno – baterija: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Povezano (podpira deljenje zvoka)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktivno (samo predstavnost)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Podpira deljenje zvoka"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktivno (samo predstavnost), samo levo"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktivno (samo predstavnost), samo desno"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktivno (samo predstavnost), levo in desno"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Upodabljanje s strojnim pospeševanjem"</string> <string name="media_category" msgid="8122076702526144053">"Predstavnost"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Spremljanje"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strog način je omogočen"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Osveži zaslon pri dolgih postopkih v glavni niti."</string> <string name="pointer_location" msgid="7516929526199520173">"Mesto kazalca"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Izvedba spletnega pogleda"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Nastavitev izvedbe spletnega pogleda"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Ta izbira ni več veljavna. Poskusite znova."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Način barv slike"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Uporaba sRGB-ja"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Onemogočeno"</string> diff --git a/packages/SettingsLib/res/values-sq/arrays.xml b/packages/SettingsLib/res/values-sq/arrays.xml index 3b0994a7d93f..98429cee9df9 100644 --- a/packages/SettingsLib/res/values-sq/arrays.xml +++ b/packages/SettingsLib/res/values-sq/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Vetëm ekrani i pajisjes (parazgjedhja)"</item> + <item msgid="9161645858025071955">"Ekrani i jashtëm"</item> + <item msgid="23651860565814477">"Prekja e fundit e shiritit të statusit"</item> + <item msgid="7521112827893653392">"Bazuar te fokusi"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Shfaq hijen vetëm në ekranin e pajisjes"</item> + <item msgid="1955398604822147783">"Shfaq panelin në një ekran të vetëm të jashtëm"</item> + <item msgid="391477482416751568">"Shfaq panelin në ekranin me shiritin e statusit të të cilit është ndërvepruar së fundi"</item> + <item msgid="1746820128097981528">"Shfaq panelin në ekranin e fokusuar së fundi"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 2d2c02b31df3..4e6ec9f96284 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ambienti rrethues nuk mund të përditësohej"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktiv (vetëm për media). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> bateri."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiv (vetëm për media). Majtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> bateri, djathtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> bateri."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Lidhur (mbështet ndarjen e audios). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> bateri."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Lidhur (mbështet ndarjen e audios). Majtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> bateri, djathtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> bateri."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Lidhur (mbështet ndarjen e audios). Majtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> bateri."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Lidhur (mbështet ndarjen e audios). Djathtas: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> bateri."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Lidhur (mbështet ndarjen e audios)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (vetëm për media)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Mbështet ndarjen e audios"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (vetëm për media), vetëm majtas"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (vetëm për media), vetëm djathtas"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (vetëm për media), majtas dhe djathtas"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Interpretimi i përshpejtuar i harduerit"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitorimi"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Aktivizo modalitetin e rreptë"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Ndriço ekranin kur aplikacionet kryejnë operacione të gjata teksa bashkëveprojnë"</string> <string name="pointer_location" msgid="7516929526199520173">"Vendndodhja e treguesit"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Zbatimi i WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Cakto zbatimin e WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Kjo zgjedhje nuk është më e vlefshme. Provo përsëri."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Modalitti i ngjyrave të figurës"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Përdor sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Çaktivizuar"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index c053094f3915..96924b9e3cee 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ажурирање окружења није успело"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Активно (само за медије). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Активно (само за медије). Лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерије."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Повезано (подржава дељење звука), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Повезано (подржава дељење звука), лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерије."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Повезано (подржава дељење звука). Лево: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Повезано (подржава дељење звука). Десно: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерије."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Повезано (подржава дељење звука)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активан (само за медије)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Подржава дељење звука"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активан (само за медије), само лево"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активан (само за медије), само десно"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активан (само за медије), лево и десно"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Хардверски убрзано приказивање"</string> <string name="media_category" msgid="8122076702526144053">"Медији"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Надгледање"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Омогућен је строги режим"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Екран трепери када апликације обављају дуге операције на главној нити"</string> <string name="pointer_location" msgid="7516929526199520173">"Локација показивача"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Примена WebView-а"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Подесите примену WebView-а"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Овај избор више није важећи. Пробајте поново."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Режим боја слика"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Користи sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Онемогућено је"</string> diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml index 8a77fdd11742..1a8c9d89a063 100644 --- a/packages/SettingsLib/res/values-sv/arrays.xml +++ b/packages/SettingsLib/res/values-sv/arrays.xml @@ -295,7 +295,7 @@ <item msgid="7521112827893653392">"Fokusbaserad"</item> </string-array> <string-array name="shade_display_awareness_summaries"> - <item msgid="2964753205732912921">"Visa endast skugga på enhetens skärm"</item> + <item msgid="2964753205732912921">"Visa panelen endast på enhetens skärm"</item> <item msgid="1955398604822147783">"Visa skugga på en enda extern skärm"</item> <item msgid="391477482416751568">"Visa skugga på skärmen där statusfältet senast interagerades med"</item> <item msgid="1746820128097981528">"Visa skugga på skärmen som sist var i fokus"</item> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index e0897cb87e54..3c7aff69fd73 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Det gick inte att uppdatera omgivningsläget"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktiv (endast media). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiv (endast media). V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Ansluten (ljuddelning stöds). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Ansluten (ljuddelning stöds). V: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, H: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Ansluten (ljuddelning stöds). Vänster: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Ansluten (ljuddelning stöds). Höger: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> batteri."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Ansluten (ljuddelning stöds)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktiv (endast media)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Ljuddelning stöds"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktiv (endast media), endast vänster"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktiv (endast media), endast höger"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktiv (endast media), vänster och höger"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Hårdvaruaccelererad rendering"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Övervakning"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Strikt läge aktiverat"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Tänd skärm när app gör omfattande åtgärd på huvudtråd"</string> <string name="pointer_location" msgid="7516929526199520173">"Pekarens plats"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Ange WebView-implementering"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Det här alternativet är inte längre giltigt. Försök igen."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Färgläge för bilder"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Använd sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Inaktiverad"</string> diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml index 652c3588d694..2ec62562f9fb 100644 --- a/packages/SettingsLib/res/values-sw/arrays.xml +++ b/packages/SettingsLib/res/values-sw/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Kwenye skrini ya kifaa pekee (Chaguomsingi)"</item> + <item msgid="9161645858025071955">"Skrini ya nje"</item> + <item msgid="23651860565814477">"Matumizi ya hivi majuzi zaidi ya sehemu ya arifa"</item> + <item msgid="7521112827893653392">"Inayoangaziwa"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Onyesha kiwango kwenye skrini ya kifaa pekee"</item> + <item msgid="1955398604822147783">"Onyesha kiwango kwenye skrini moja ya nje"</item> + <item msgid="391477482416751568">"Onyesha kiwango kwenye skrini ambayo sehemu yake ya arifa ilitumiwa hivi majuzi"</item> + <item msgid="1746820128097981528">"Onyesha kiwango kwenye skrini iliyoangaziwa mwisho kabisa"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index f12597f640a5..4f520b499b85 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Imeshindwa kusasisha mazingira"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Inatumika (maudhui pekee). Chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Inatumika (maudhui pekee), Kushoto: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Kulia: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Imeunganishwa (inaweza kutumia kipengele cha kusikiliza pamoja). Chaji imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Imeunganishwa (inaweza kutumia kipengele cha kusikiliza pamoja). Kushoto: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Kulia: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Imeunganishwa (inaweza kutumia kipengele cha kusikiliza pamoja). Kushoto: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Imeunganishwa (inaweza kutumia kipengele cha kusikiliza pamoja). Kulia: chaji ya betri imefika <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Imeunganishwa (inaweza kusikiliza pamoja)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Inatumika (maudhui pekee)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Inaweza kutumia kipengele cha kusikiliza pamoja"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Inatumika (maudhui pekee), kushoto pekee"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Inatumika (maudhui pekee), kulia pekee"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Inatumika (maudhui pekee), kushoto na kulia"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Utekelezaji wa maunzi ulioharakishwa"</string> <string name="media_category" msgid="8122076702526144053">"Maudhui"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Ufuatiliaji"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Hali makinifu imewashwa"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Fanya skrini imemeteke programu zinapoendeleza shughuli ndefu kwenye skrini kuu"</string> <string name="pointer_location" msgid="7516929526199520173">"Mahali pa kiashiria"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Utekelezaji wa WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Weka utekelezaji wa WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Chaguo hili halipo tena. Jaribu tena."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Hali ya rangi ya picha"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Tumia sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Imezimwa"</string> diff --git a/packages/SettingsLib/res/values-ta/arrays.xml b/packages/SettingsLib/res/values-ta/arrays.xml index 503cd8f97046..f42e47670149 100644 --- a/packages/SettingsLib/res/values-ta/arrays.xml +++ b/packages/SettingsLib/res/values-ta/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"சாதனக் காட்சி மட்டும் (இயல்பு)"</item> + <item msgid="9161645858025071955">"வெளிப்புறக் காட்சி"</item> + <item msgid="23651860565814477">"சமீபத்திய நிலைப் பட்டித் தொடுகை"</item> + <item msgid="7521112827893653392">"ஃபோகஸ் அடிப்படையிலானது"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"சாதனக் காட்சியில் மட்டும் ஷேடைக் காட்டும்"</item> + <item msgid="1955398604822147783">"ஒற்றை வெளிப்புறக் காட்சியில் ஷேடைக் காட்டும்"</item> + <item msgid="391477482416751568">"கடைசியாக நிலைப் பட்டி தொடர்புகொண்ட ஷேடைக் காட்சியில் காட்டும்"</item> + <item msgid="1746820128097981528">"கடைசியாக ஃபோகஸ் செய்யப்பட்ட காட்சியில் ஷேடைக் காட்டும்"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 1bd2c3419860..aa345842779c 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"சுற்றுப்புறங்களைப் புதுப்பிக்க முடியவில்லை"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"செயலிலுள்ளது (மீடியா மட்டும்). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"செயலிலுள்ளது (மீடியா மட்டும்). இடது பேட்டரி: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, வலது பேட்டரி: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது). இடது பேட்டரி: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, வலது பேட்டரி: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது). இடது: - <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது). வலது: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> பேட்டரி."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"இணைக்கப்பட்டுள்ளது (ஆடியோ பகிர்வை ஆதரிக்கிறது)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"செயலிலுள்ளது (மீடியா மட்டும்)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ஆடியோ பகிர்வை ஆதரிக்கிறது"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"செயலிலுள்ளது (மீடியா மட்டும்), இடதுபுறம் மட்டும்"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"செயலிலுள்ளது (மீடியா மட்டும்), வலதுபுறம் மட்டும்"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"செயலிலுள்ளது (மீடியா மட்டும்), இடதுபுறம் மற்றும் வலதுபுறம்"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"வன்பொருள் முடுக்கத்துடன் கூடிய காட்சியாக்கம்"</string> <string name="media_category" msgid="8122076702526144053">"மீடியா"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"கண்காணித்தல்"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"நிலையான பயன்முறை இயக்கப்பட்டது"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"முக்கியத் தொடரிழையில் நீண்ட நேரம் செயல்படும்போது திரையைக் காட்சிப்படுத்தும்"</string> <string name="pointer_location" msgid="7516929526199520173">"குறிப்பான் இடம்"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView செயல்படுத்தல்"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView செயல்படுத்தலை அமை"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"இனி இந்தத் தேர்வைப் பயன்படுத்த முடியாது. மீண்டும் முயலவும்."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"படத்தின் வண்ணப் பயன்முறை"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGBஐப் பயன்படுத்தும்"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"முடக்கப்பட்டது"</string> diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml index f72e4cd9f9fe..a4e50d0c7f30 100644 --- a/packages/SettingsLib/res/values-te/arrays.xml +++ b/packages/SettingsLib/res/values-te/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"పరికర డిస్ప్లేలో మాత్రమే (ఆటోమేటిక్ సెట్టింగ్)"</item> + <item msgid="9161645858025071955">"ఎక్స్టర్నల్ డిస్ప్లే"</item> + <item msgid="23651860565814477">"తాకి ఉపయోగించగల లేటెస్ట్ స్టేటస్ బార్"</item> + <item msgid="7521112827893653392">"యాక్టివ్గా ఉన్నవి"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"షేడ్ను పరికర డిస్ప్లేలో మాత్రమే చూపండి"</item> + <item msgid="1955398604822147783">"ఒక ఎక్స్టర్నల్ డిస్ప్లేలో షేడ్ను చూపండి"</item> + <item msgid="391477482416751568">"స్టేటస్ బార్తో చివరిగా ఇంటరాక్ట్ అయిన షేడ్ను డిస్ప్లేలో చూపండి"</item> + <item msgid="1746820128097981528">"చివరగా యాక్టివ్గా ఉన్న డిస్ప్లేలో షేడ్ను చూపండి"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index 010344f2e103..cded034d5ab3 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"పరిసరాలను అప్డేట్ చేయడం సాధ్యం కాలేదు"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"యాక్టివ్ (మీడియా మాత్రమే). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"యాక్టివ్ (మీడియా మాత్రమే). ఎడమ వైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> బ్యాటరీ, కుడివైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> బ్యాటరీ."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"కనెక్ట్ చేయబడింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"కనెక్ట్ చేయబడింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది). ఎడమ వైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> బ్యాటరీ, కుడివైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> బ్యాటరీ."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"కనెక్ట్ చేయబడింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది). ఎడమ వైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"కనెక్ట్ అయింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది). కుడివైపు: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> బ్యాటరీ."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"కనెక్ట్ చేయబడింది (ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"యాక్టివ్ (మీడియా మాత్రమే)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"ఆడియో షేరింగ్కు సపోర్ట్ చేస్తుంది"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"యాక్టివ్ (మీడియా మాత్రమే), ఎడమ వైపు మాత్రమే"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"యాక్టివ్ (మీడియా మాత్రమే), కుడివైపు మాత్రమే"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"యాక్టివ్ (మీడియా మాత్రమే), ఎడమ, కుడివైపు మాత్రమే"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"హార్డ్వేర్ యాగ్జిలరేషన్ ఆధారిత రెండరింగ్"</string> <string name="media_category" msgid="8122076702526144053">"మీడియా"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"పర్యవేక్షణ"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"స్ట్రిక్ట్ మోడ్ ఎనేబుల్డ్"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"యాప్లు ప్రధాన థ్రెడ్లో సుదీర్ఘ చర్యలు చేసేటప్పుడు స్క్రీన్ను ఫ్లాష్ చేయండి"</string> <string name="pointer_location" msgid="7516929526199520173">"పాయింటర్ లొకేషన్"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ఈ ఎంపిక ఇప్పుడు లేదు. మళ్లీ ట్రై చేయండి."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"చిత్రం రంగు మోడ్"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ఉపయోగిస్తుంది"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"డిజేబుల్ చేయబడింది"</string> diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml index adb274d26f9c..ad0f6bc840d7 100644 --- a/packages/SettingsLib/res/values-th/arrays.xml +++ b/packages/SettingsLib/res/values-th/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"จอแสดงผลของอุปกรณ์เท่านั้น (ค่าเริ่มต้น)"</item> + <item msgid="9161645858025071955">"จอแสดงผลภายนอก"</item> + <item msgid="23651860565814477">"การแตะแถบสถานะล่าสุด"</item> + <item msgid="7521112827893653392">"Focus-based"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"แสดงเฉดสีในจอแสดงผลของอุปกรณ์เท่านั้น"</item> + <item msgid="1955398604822147783">"แสดงเฉดสีในจอแสดงผลภายนอกเครื่องเดียว"</item> + <item msgid="391477482416751568">"แสดงเฉดสีในจอแสดงผลที่มีการโต้ตอบกับแถบสถานะล่าสุด"</item> + <item msgid="1746820128097981528">"แสดงเฉดสีในจอแสดงผลที่โฟกัสล่าสุด"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index 9b4d408c4cf1..eaf256d520df 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"อัปเดตเสียงแวดล้อมไม่ได้"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"ใช้งานอยู่ (สื่อเท่านั้น) แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"ใช้งานอยู่ (สื่อเท่านั้น) แบตเตอรี่ข้างซ้าย: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ข้างขวา: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง) แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง) แบตเตอรี่ข้างซ้าย: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, ข้างขวา: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง) ซ้าย: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง) ขวา: แบตเตอรี่ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"เชื่อมต่อแล้ว (รองรับการแชร์เสียง)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"ใช้งานอยู่ (สื่อเท่านั้น)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"รองรับการแชร์เสียง"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"ใช้งานอยู่ (สื่อเท่านั้น), ซ้ายเท่านั้น"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"ใช้งานอยู่ (สื่อเท่านั้น), ขวาเท่านั้น"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"ใช้งานอยู่ (สื่อเท่านั้น), ซ้ายและขวา"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"การแสดงผลที่มีการเร่งด้วยฮาร์ดแวร์"</string> <string name="media_category" msgid="8122076702526144053">"สื่อ"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"การตรวจสอบ"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"เปิดใช้งานโหมดเข้มงวด"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"กะพริบหน้าจอเมื่อแอปทำงานในเทรดหลักนาน"</string> <string name="pointer_location" msgid="7516929526199520173">"ตำแหน่งของตัวชี้"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"การใช้งาน WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"ตั้งค่าการใช้งาน WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ตัวเลือกนี้ใช้ไม่ได้อีกต่อไป โปรดลองอีกครั้ง"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"โหมดสีของรูปภาพ"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"ใช้ sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"ปิดใช้"</string> diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml index 0153375a5c2c..b1dd61af32af 100644 --- a/packages/SettingsLib/res/values-tl/arrays.xml +++ b/packages/SettingsLib/res/values-tl/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Display ng device lang (Default)"</item> + <item msgid="9161645858025071955">"External na display"</item> + <item msgid="23651860565814477">"Pinakahuling pagpindot sa status bar"</item> + <item msgid="7521112827893653392">"Focus-based"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Ipakita ang shade sa display ng device lang"</item> + <item msgid="1955398604822147783">"Ipakita ang shade sa isang external na display"</item> + <item msgid="391477482416751568">"Ipakita ang shade sa display kung saan may kamakailang nakipag-ugnayan sa status bar nito"</item> + <item msgid="1746820128097981528">"Ipakita ang shade sa pinakahuling na-focus na display"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 4cd2f5f3c675..b6d8d190d1ca 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Hindi ma-update ang paligid"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktibo (media lang). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktibo (media lang). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterya."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Nakakonekta (sinusuportahan ang pag-share ng audio), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Nakakonekta (sinusuportahan ang pag-share ng audio). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> baterya."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Nakakonekta (sinusuportahan ang pag-share ng audio). Kaliwa: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Nakakonekta (sinusuportahan ang pag-share ng audio). Kanan: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterya."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Nakakonekta (sinusuportahan ang pag-share ng audio)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Aktibo (media lang)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Sinusuportahan ang pag-share ng audio"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Aktibo (media lang), kaliwa lang"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Aktibo (media lang), kanan lang"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Aktibo (media lang), kaliwa at kanan"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Pag-render na pinapabilis ng hardware"</string> <string name="media_category" msgid="8122076702526144053">"Media"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Pagsubaybay"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Enabled ang strict mode"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"I-flash ang screen pag may long ops ang app sa main thread"</string> <string name="pointer_location" msgid="7516929526199520173">"Lokasyon ng pointer"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Pagpapatupad sa WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Itakda ang pagpapatupad sa WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Wala nang bisa ang napiling ito. Subukang muli."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Mode ng kulay ng larawan"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Gamitin ang sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Naka-disable"</string> diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml index 6fbbb129b56b..04697f22d0ee 100644 --- a/packages/SettingsLib/res/values-tr/arrays.xml +++ b/packages/SettingsLib/res/values-tr/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Yalnızca cihaz ekranı (Varsayılan)"</item> + <item msgid="9161645858025071955">"Harici ekran"</item> + <item msgid="23651860565814477">"Durum çubuğuyla yapılan en son etkileşim"</item> + <item msgid="7521112827893653392">"Odaklanmaya dayalı"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Gölgeyi yalnızca cihaz ekranında göster"</item> + <item msgid="1955398604822147783">"Gölgeyi tek bir harici ekranda göster"</item> + <item msgid="391477482416751568">"Gölgeyi, durum çubuğuyla en son etkileşim yapılan ekranda göster"</item> + <item msgid="1746820128097981528">"Gölgeyi en son odaklanılan ekranda göster"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index c99322324a66..c4cbaf69b5a9 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Çevredeki sesler güncellenemedi"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Etkin (yalnızca medya). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pil seviyesi."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Etkin (yalnızca medya). Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pil seviyesi."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Bağlı (ses paylaşımını destekler). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pil seviyesi."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Bağlı (ses paylaşımını destekler). Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pil seviyesi."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Bağlı (ses paylaşımını destekler). Sol: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pil seviyesi."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Bağlı (ses paylaşımını destekler). Sağ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pil seviyesi."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Bağlı (ses paylaşımını destekler)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Etkin (yalnızca medya)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Ses paylaşımını destekler"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Etkin (yalnızca medya), yalnızca sol"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Etkin (yalnızca medya), yalnızca sağ"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Etkin (yalnızca medya), sol ve sağ"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Donanım hızlandırmalı oluşturma"</string> <string name="media_category" msgid="8122076702526144053">"Medya"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"İzleme"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Yüksek düzey modu etkin"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Uygulamalar ana iş parçacığında uzun işlem yaparken ekranı yanıp söndür"</string> <string name="pointer_location" msgid="7516929526199520173">"İşaretçi konumu"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Web Görünümü kullanımı"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Web Görünümü kullanımını ayarla"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Bu seçenek artık geçerli değil. Tekrar deneyin."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Resim renk modu"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB\'yi kullan"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Devre dışı"</string> diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml index a371c9c5d0f5..569d6f342d8f 100644 --- a/packages/SettingsLib/res/values-uk/arrays.xml +++ b/packages/SettingsLib/res/values-uk/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Лише екран пристрою (за умовчанням)"</item> + <item msgid="9161645858025071955">"Зовнішній дисплей"</item> + <item msgid="23651860565814477">"Останнє натискання рядка стану"</item> + <item msgid="7521112827893653392">"На основі фокусування"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Показувати панель лише на екрані пристрою"</item> + <item msgid="1955398604822147783">"Показувати панель на одному зовнішньому дисплеї"</item> + <item msgid="391477482416751568">"Показувати панель на дисплеї, де відбулася остання взаємодія з рядком стану"</item> + <item msgid="1746820128097981528">"Показувати панель на останньому активному дисплеї"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index fd1ade641d95..ecff5722472c 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Не вдалось оновити стан оточення"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Активне з’єднання (лише для мультимедіа). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Активне з’єднання (лише для мультимедіа). Рівень заряду: лівий <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, правий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Підключено (підтримує надсилання аудіо). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Підключено (підтримує надсилання аудіо). Лівий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, правий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> заряду акумулятора."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Підключено (підтримує надсилання аудіо). Лівий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Підключено (підтримує надсилання аудіо). Правий: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> заряду акумулятора."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Підключено (підтримує надсилання аудіо)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Активно (лише для мультимедіа)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Підтримує надсилання аудіо"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Активно (лише для мультимедіа); лише лівий"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Активно (лише для мультимедіа); лише правий"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Активно (лише для мультимедіа); лівий і правий"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Апаратне прискорення"</string> <string name="media_category" msgid="8122076702526144053">"Медіа"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Моніторинг"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Строгий режим увімкнено"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Підсвічувати екран під час довгострокових операцій"</string> <string name="pointer_location" msgid="7516929526199520173">"Розташування курсора"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Застосування WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Налаштувати застосування WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Ця опція більше не дійсна. Повторіть спробу."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Режим кольору"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Використовувати sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Вимкнено"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index 13ffeb125972..34071147f5d9 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"اطراف کو اپ ڈیٹ نہیں کیا جا سکا"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"فعال (صرف میڈیا)۔ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری۔"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"فعال (صرف میڈیا)۔ L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> بیٹری۔"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)۔ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری۔"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)۔ L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> بیٹری۔"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)۔ بائيں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری۔"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)۔ دائيں: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> بیٹری۔"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"منسلک ہے (آڈیو کے اشتراک کو سپورٹ کرتا ہے)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"فعال (صرف میڈیا)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"آڈیو کے اشتراک کو سپورٹ کرتا ہے"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"فعال (صرف میڈیا)، صرف بائیں"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"فعال (صرف میڈیا)، صرف دائیں"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"فعال (صرف میڈیا)، بائیں اور دائیں"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"ہارڈ ویئر کے ذریعے تیز کردہ رینڈرنگ"</string> <string name="media_category" msgid="8122076702526144053">"میڈیا"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"مانیٹر کرنا"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"سخت وضع فعال ہے"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"ایپس کے اصل تھریڈ پر طویل اعمال انجام دیتے وقت اسکرین کو فلیش کریں"</string> <string name="pointer_location" msgid="7516929526199520173">"پوائنٹر مقام"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView کا نفاذ"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView کا نفاذ سیٹ کریں"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"یہ انتخاب اب درست نہیں رہا۔ دوبارہ کوشش کریں۔"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"تصویری رنگ موڈ"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB استعمال کریں"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"غیر فعال"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 04bd7fccefaa..bff79933c10c 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Atrof-muhit yangilanmadi"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Faol (faqat media uchun) Quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Faol (faqat media uchun), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (L), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (R)"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Ulangan (audio yuborish mumkin), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Ulangan (audio yuborish mumkin), quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (L), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (R)"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Ulangan (audio yuborish mumkin). Quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (chap)."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Ulangan (audio yuborish mumkin). Quvvat: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (oʻng)."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Ulangan (audio yuborish mumkin)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Faol (faqat media uchun)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Audio yuborishi mumkin"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Faol (faqat media uchun), faqat chap"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Faol (faqat media uchun), faqat oʻng"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Faol (faqat media uchun), chap va oʻng"</string> @@ -250,11 +270,11 @@ <string name="enable_adb" msgid="8072776357237289039">"USB orqali nosozliklarni aniqlash"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"USB orqali kompyuterga ulanganda tuzatish rejimi yoqilsin"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"USB orqali nosozliklarni tuzatishni taqiqlash"</string> - <string name="enable_adb_wireless" msgid="6973226350963971018">"Wi-Fi orqali debagging"</string> + <string name="enable_adb_wireless" msgid="6973226350963971018">"Wi-Fi orqali debaging"</string> <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Wi‑Fi tarmoqqa ulanganda nosozliklarni aniqlash rejimi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Xato"</string> - <string name="adb_wireless_settings" msgid="2295017847215680229">"Wi-Fi orqali debagging"</string> - <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Mavjud qurilmalarni koʻrish va ulardan foydalanish uchun Wi-Fi orqali debagging funksiyasini yoqing"</string> + <string name="adb_wireless_settings" msgid="2295017847215680229">"Wi-Fi orqali debaging"</string> + <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Mavjud qurilmalarni koʻrish va ulardan foydalanish uchun Wi-Fi orqali debaging funksiyasini yoqing"</string> <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Qurilmani QR kod orqali ulash"</string> <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"QR kod skaneri yordamida yangi qurilmalarni ulang"</string> <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Qurilmani ulanish kodi orqali ulash"</string> @@ -345,8 +365,8 @@ <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Modem rejimida apparatli tezlatishdan foydalanish (mavjud bo‘lsa)."</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB orqali nosozliklarni tuzatishga ruxsat berilsinmi?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB orqali nosozliklarni aniqlash faqat dasturlash maqsadlarida yoqiladi. Undan maʼlumotlarni qurilmangiz va kompyuter o‘rtasida ko‘chirish, ilovalarni xabarnomasiz o‘rnatish va jurnal maʼlumotlarini o‘qish uchun foydalaniladi."</string> - <string name="adbwifi_warning_title" msgid="727104571653031865">"Wi-Fi orqali debagging uchun ruxsat berilsinmi?"</string> - <string name="adbwifi_warning_message" msgid="8005936574322702388">"Wi-Fi orqali debagging faqat dasturlash maqsadlarida yoqiladi. Undan maʼlumotlarni qurilmangiz va kompyuter oʻrtasida koʻchirish, ilovalarni bildirishnomasiz oʻrnatish va jurnal maʼlumotlarini oʻqish uchun foydalaniladi."</string> + <string name="adbwifi_warning_title" msgid="727104571653031865">"Wi-Fi orqali debaging uchun ruxsat berilsinmi?"</string> + <string name="adbwifi_warning_message" msgid="8005936574322702388">"Wi-Fi orqali debaging faqat dasturlash maqsadlarida yoqiladi. Undan maʼlumotlarni qurilmangiz va kompyuter oʻrtasida koʻchirish, ilovalarni bildirishnomasiz oʻrnatish va jurnal maʼlumotlarini oʻqish uchun foydalaniladi."</string> <string name="adb_keys_warning_message" msgid="2968555274488101220">"USB orqali nosozliklarni tuzatishga berilgan ruxsat siz hisobingizga kirgan barcha kompyuterlar uchun bekor qilinsinmi?"</string> <string name="dev_settings_warning_title" msgid="8251234890169074553">"Dasturlash sozlamalariga ruxsat berilsinmi?"</string> <string name="dev_settings_warning_message" msgid="37741686486073668">"Bu sozlamalar faqat dasturlash maqsadlariga mo‘ljallangan. Shuning uchun, ular qurilmangizga va undagi ilovalariga shikast yetkazib, noto‘g‘ri ishlashiga sabab bo‘lishi mumkin."</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Vizualizatsiyani apparatli tezlatish"</string> <string name="media_category" msgid="8122076702526144053">"Multimedia"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Monitoring"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Qat’iy rejim yoqilgan"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Uzun amallar vaqtida ekranni miltillatish"</string> <string name="pointer_location" msgid="7516929526199520173">"Kursor joylashuvi"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ta’minotchisi"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"WebView ta’minotchisini sozlash"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Bu variant endi yaroqsiz. Qaytadan urining."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Rang rejimi"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"sRGB ranglaridan foydalanish"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Oʻchiq"</string> diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml index 8e4cf53cfc39..daddccc07b1f 100644 --- a/packages/SettingsLib/res/values-vi/arrays.xml +++ b/packages/SettingsLib/res/values-vi/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Chỉ hiển thị trên thiết bị (Mặc định)"</item> + <item msgid="9161645858025071955">"Màn hình ngoài"</item> + <item msgid="23651860565814477">"Lần gần đây nhất chạm vào thanh trạng thái"</item> + <item msgid="7521112827893653392">"Theo tiêu điểm"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Chỉ hiện ngăn thông báo trên màn hình thiết bị"</item> + <item msgid="1955398604822147783">"Hiện ngăn trên một màn hình ngoài"</item> + <item msgid="391477482416751568">"Hiện ngăn trên màn hình mà gần đây nhất người dùng đã tương tác với thanh trạng thái của màn hình đó"</item> + <item msgid="1746820128097981528">"Hiện ngăn trên màn hình mà gần đây nhất người dùng đã đặt tiêu điểm"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 2763c017398b..cb0a875a8d7a 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Không cập nhật được âm lượng xung quanh"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Đang hoạt động (chỉ phát nội dung đa phương tiện). Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Đang hoạt động (chỉ phát nội dung đa phương tiện). Bên trái: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pin. Bên phải: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pin."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh). Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh). Bên trái: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pin. Bên phải: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pin."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh). Bên trái: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh). Bên phải: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Đã kết nối (có hỗ trợ tính năng chia sẻ âm thanh)."</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Đang hoạt động (chỉ phát nội dung đa phương tiện)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Hỗ trợ tính năng chia sẻ âm thanh"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Đang hoạt động (chỉ phát nội dung đa phương tiện), chỉ dùng tai nghe bên trái"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Đang hoạt động (chỉ phát nội dung đa phương tiện), chỉ dùng tai nghe bên phải"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Đang hoạt động (chỉ phát nội dung đa phương tiện), đang dùng cả tai nghe bên trái và phải"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Kết xuất có tăng tốc phần cứng"</string> <string name="media_category" msgid="8122076702526144053">"Phương tiện"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Giám sát"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Luôn bật chế độ nghiêm ngặt"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Màn hình nháy khi ứng dụng thực hiện các hoạt động dài trên luồng chính"</string> <string name="pointer_location" msgid="7516929526199520173">"Vị trí con trỏ"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Triển khai WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Đặt triển khai WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Lựa chọn này không còn hợp lệ nữa. Hãy thử lại."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Chế độ màu của ảnh"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Sử dụng sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Đã tắt"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml index 5c82865d3d52..204bccfff714 100644 --- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml +++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"仅设备显示屏(默认)"</item> + <item msgid="9161645858025071955">"外接显示屏"</item> + <item msgid="23651860565814477">"最近一次触摸状态栏"</item> + <item msgid="7521112827893653392">"基于焦点"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"仅在设备显示屏上显示通知栏"</item> + <item msgid="1955398604822147783">"在单个外接显示屏上显示通知栏"</item> + <item msgid="391477482416751568">"在上次与状态栏互动的显示屏上显示通知栏"</item> + <item msgid="1746820128097981528">"在最近一次获得焦点的显示屏上显示通知栏"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 934c525661e5..f13f7d91bd71 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"无法更新周围声音"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"使用中(仅限媒体)。电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"使用中(仅限媒体)。左侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"已连接(支持音频分享)。电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"已连接(支持音频分享)。左侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"已连接(支持音频分享)。左侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"已连接(支持音频分享)。右侧电池电量为 <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"已连接(支持音频分享)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"使用中(仅限媒体)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"支持音频分享"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"使用中(仅限媒体),仅左侧"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"使用中(仅限媒体),仅右侧"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"使用中(仅限媒体),左侧和右侧"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"硬件加速渲染"</string> <string name="media_category" msgid="8122076702526144053">"媒体"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"监控"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"启用严格模式"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"应用在主线程上执行长时间操作时闪烁屏幕"</string> <string name="pointer_location" msgid="7516929526199520173">"指针位置"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 实现"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"设置 WebView 实现"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"此选项已失效,请重试。"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"图片颜色模式"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"使用 sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"已停用"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml index 2e060595b299..f70b02d2e017 100644 --- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml +++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"只限裝置顯示屏 (預設)"</item> + <item msgid="9161645858025071955">"外部顯示屏"</item> + <item msgid="23651860565814477">"最近一次觸碰狀態列"</item> + <item msgid="7521112827893653392">"突顯"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"只在裝置顯示屏上顯示陰影"</item> + <item msgid="1955398604822147783">"在單一外接螢幕顯示通知欄"</item> + <item msgid="391477482416751568">"在上次使用狀態列的螢幕上顯示通知欄"</item> + <item msgid="1746820128097981528">"在最新使用的螢幕顯示通知欄"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index 037f531b7c02..14976e098efa 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"無法更新環境聲音"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"啟用 (只限媒體)。<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量。"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"啟用 (只限媒體),左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> 電量,右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 電量。"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"已連線 (支援音訊分享功能),<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量。"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"已連線 (支援音訊分享功能),左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> 電量,右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> 電量。"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"已連線 (支援音訊分享功能)。左側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量。"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"已連線 (支援音訊分享功能)。右側:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> 電量。"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"已連線 (支援音訊分享功能)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"啟用 (只限媒體)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"支援音訊分享功能"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"左側啟用 (只限媒體)"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"右側啟用 (只限媒體)"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"右側同時啟用 (只限媒體)"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"硬件加速轉譯"</string> <string name="media_category" msgid="8122076702526144053">"媒體"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"監控"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"嚴格模式已啟用"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"當應用程式在主執行緒中進行長時間作業時,讓螢幕閃爍"</string> <string name="pointer_location" msgid="7516929526199520173">"指標位置"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 設置"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"設定 WebView 設置"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"此選擇已失效,請再試一次。"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"相片顏色模式"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"使用 sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"已停用"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml index 5b48ad40c63c..6ac8ff5b3757 100644 --- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml +++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"僅裝置螢幕 (預設)"</item> + <item msgid="9161645858025071955">"外接螢幕"</item> + <item msgid="23651860565814477">"最近一次觸碰狀態列"</item> + <item msgid="7521112827893653392">"使用中的螢幕"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"只在裝置螢幕顯示通知欄"</item> + <item msgid="1955398604822147783">"在單一外接螢幕顯示通知欄"</item> + <item msgid="391477482416751568">"在上次使用狀態列的螢幕上顯示通知欄"</item> + <item msgid="1746820128097981528">"在最新使用的螢幕顯示通知欄"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"預設螢幕"</item> + <item msgid="774789415968826925">"任何外接螢幕"</item> + <item msgid="7880769915418638436">"最新觸控狀態列"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 0ef65e6151d1..b65cb4f5ecbe 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"無法更新環境狀態"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"已啟用 (僅限媒體)。電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"已啟用 (僅限媒體)。左側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"已連線 (支援音訊分享)。電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"已連線 (支援音訊分享)。左側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>,右側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"已連線 (支援音訊分享)。左側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"已連線 (支援音訊分享)。右側電量:<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>。"</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"已連線 (支援音訊分享)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"啟用 (僅限媒體)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"支援音訊分享"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"左側啟用 (僅限媒體)"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"右側啟用 (僅限媒體)"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"左右側同時啟用 (僅限媒體)"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"硬體加速轉譯"</string> <string name="media_category" msgid="8122076702526144053">"媒體"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"監控"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"嚴格模式已啟用"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"當應用程式在主執行緒中進行長時間作業時,讓螢幕閃爍"</string> <string name="pointer_location" msgid="7516929526199520173">"指標位置"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 實作"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"設定 WebView 實作"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"這個選項已失效,請再試一次。"</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"螢幕色彩模式"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"使用 sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"已停用"</string> diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml index 1a61f8b3d326..25f9592d9d5d 100644 --- a/packages/SettingsLib/res/values-zu/arrays.xml +++ b/packages/SettingsLib/res/values-zu/arrays.xml @@ -288,10 +288,22 @@ <item msgid="3753634915787796632">"2"</item> <item msgid="4779928470672877922">"3"</item> </string-array> - <!-- no translation found for shade_display_awareness_entries:2 (23651860565814477) --> - <!-- no translation found for shade_display_awareness_entries:3 (7521112827893653392) --> - <!-- no translation found for shade_display_awareness_summaries:1 (1955398604822147783) --> - <!-- no translation found for shade_display_awareness_summaries:2 (391477482416751568) --> - <!-- no translation found for shade_display_awareness_summaries:3 (1746820128097981528) --> - <!-- no translation found for shade_display_awareness_values:3 (4313165186636015195) --> + <string-array name="shade_display_awareness_entries"> + <item msgid="816770658383209617">"Ukuboniswa kwedivayisi kuphela (Okuzenzakalelayo)"</item> + <item msgid="9161645858025071955">"Ukubonisa Kwangaphandle"</item> + <item msgid="23651860565814477">"Thinta ibha yesimo yamuva"</item> + <item msgid="7521112827893653392">"Kusekelwe ekugxileni"</item> + </string-array> + <string-array name="shade_display_awareness_summaries"> + <item msgid="2964753205732912921">"Bonisa umthunzi esibonisini sedivayisi kuphela"</item> + <item msgid="1955398604822147783">"Bonisa umthunzi esibonisini esisodwa sangaphandle"</item> + <item msgid="391477482416751568">"Bonisa umthunzi esibonisini kokudlule ebesinesimo sebha okuxhunyanwe naso"</item> + <item msgid="1746820128097981528">"Bonisa umthunzi esibonisini sokugcina okugxilwe kuso"</item> + </string-array> + <string-array name="shade_display_awareness_values"> + <item msgid="3055776101992426514">"default_display"</item> + <item msgid="774789415968826925">"any_external_display"</item> + <item msgid="7880769915418638436">"status_bar_latest_touch"</item> + <item msgid="4313165186636015195">"focused_display"</item> + </string-array> </resources> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index de626284ff87..859c153dd59d 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -113,13 +113,33 @@ <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Ayikwazanga ukubuyekeza izindawo ezizungezile"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Iyasebenza (imidiya kuphela). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ibhethri."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Iyasebenza (imidiya kuphela). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ibhethri."</string> + <!-- no translation found for bluetooth_guest_battery_level (2820003593899467676) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered (5404013822067644960) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level (7928347900623812299) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_battery_level_untethered (4458143141394300892) --> + <skip /> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ibhethri."</string> <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> ibhethri."</string> <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe). Kwesokudla: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ibhethri."</string> <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe). Kwesokudla: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> ibhethri."</string> <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Ixhunyiwe (isekela ukwabelana ngokuqoshiwe)"</string> + <!-- no translation found for bluetooth_guest_battery_level_lea_support (8098327939585013928) --> + <skip /> + <!-- no translation found for bluetooth_guest_battery_level_untethered_lea_support (3701035025565668360) --> + <skip /> + <!-- no translation found for bluetooth_guest_no_battery_level_lea_support (2977038548753103470) --> + <skip /> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Kuyasebenza (imidiya kuphela)"</string> + <!-- no translation found for bluetooth_guest_no_battery_level (9122974160381136920) --> + <skip /> + <!-- no translation found for bluetooth_guest_media_only_no_battery_level (7666347601796705721) --> + <skip /> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Isekela ukwabelana ngokuqoshiwe"</string> + <!-- no translation found for bluetooth_guest_saved_device_lea_support (5621291599518569876) --> + <skip /> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Iyasebenza (imidiya kuphela), ngakwesokunxele kuphela"</string> <string name="bluetooth_hearing_aid_media_only_right_active" msgid="3854140683042617230">"Kuyasebenza (imidiya kuphela), ngakwesokudla kuphela"</string> <string name="bluetooth_hearing_aid_media_only_left_and_right_active" msgid="1299913413062528417">"Kuyasebenza (imidiya kuphela), ngakwesokunxele nakwesokudla"</string> @@ -376,6 +396,8 @@ <string name="debug_hw_drawing_category" msgid="5830815169336975162">"Ukunikezelwa okusheshisiwe kwezingxenyekazi zekhompyutha"</string> <string name="media_category" msgid="8122076702526144053">"Imidiya"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"Ukwengamela"</string> + <!-- no translation found for window_management_category (2015535427098365170) --> + <skip /> <string name="strict_mode" msgid="889864762140862437">"Imodi eqinile ivumelwe"</string> <string name="strict_mode_summary" msgid="1838248687233554654">"Ukuphazimisa isikrini uma izinhlelo zokusebenza ziyenza umsebenzi ngesikhathi eside kuchungechunge olukhulu"</string> <string name="pointer_location" msgid="7516929526199520173">"Isikhombi sendawo"</string> @@ -470,6 +492,12 @@ <string name="select_webview_provider_title" msgid="3917815648099445503">"Ukufakwa ke-WebView"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Sesba ukufakwa kwe-WebView"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Lokhu kukhetha akusavumelekile. Zama futhi."</string> + <!-- no translation found for webview_launch_devtools_title (8009687433555367112) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_package (3182544553665113721) --> + <skip /> + <!-- no translation found for webview_launch_devtools_no_activity (4066006313619617140) --> + <skip /> <string name="picture_color_mode" msgid="1013807330552931903">"Imodi yombala wesithombe"</string> <string name="picture_color_mode_desc" msgid="151780973768136200">"Sebenzisa i-sRGB"</string> <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Kukhutshaziwe"</string> diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml index 3326b6034237..7ab096fae0db 100644 --- a/packages/SettingsLib/res/values/styles.xml +++ b/packages/SettingsLib/res/values/styles.xml @@ -116,4 +116,13 @@ <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> <item name="android:textSize">16dp</item> </style> + + <style name="Theme.Transparent" parent="@android:style/Theme.DeviceDefault.Settings"> + <item name="android:windowActionBar">false</item> + <item name="android:windowNoTitle">true</item> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowContentOverlay">@null</item> + </style> + </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 4110d536da61..ba7270940a7c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -585,7 +585,8 @@ public class ApplicationsState { legacy, true); } catch (RemoteException ignored) { } - } catch (NameNotFoundException | IOException e) { + } catch ( + IllegalArgumentException | NameNotFoundException | IOException e) { Log.w(TAG, "Failed to query stats: " + e); try { mBackgroundHandler.mStatsObserver.onGetStatsCompleted( diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index a00484ac28ab..522a436b0732 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -555,22 +555,17 @@ public class BluetoothUtils { * connected 2) is Hearing Aid or LE Audio OR 3) connected profile matches currentAudioProfile * * @param cachedDevice the CachedBluetoothDevice - * @param audioManager audio manager to get the current audio profile + * @param isOngoingCall get the current audio profile based on if in phone call * @return if the device is AvailableMediaBluetoothDevice */ @WorkerThread public static boolean isAvailableMediaBluetoothDevice( - CachedBluetoothDevice cachedDevice, AudioManager audioManager) { - int audioMode = audioManager.getMode(); + CachedBluetoothDevice cachedDevice, boolean isOngoingCall) { int currentAudioProfile; - if (audioMode == AudioManager.MODE_RINGTONE - || audioMode == AudioManager.MODE_IN_CALL - || audioMode == AudioManager.MODE_IN_COMMUNICATION) { - // in phone call + if (isOngoingCall) { currentAudioProfile = BluetoothProfile.HEADSET; } else { - // without phone call currentAudioProfile = BluetoothProfile.A2DP; } @@ -859,22 +854,17 @@ public class BluetoothUtils { * currentAudioProfile * * @param cachedDevice the CachedBluetoothDevice - * @param audioManager audio manager to get the current audio profile + * @param isOngoingCall get the current audio profile based on if in phone call * @return if the device is AvailableMediaBluetoothDevice */ @WorkerThread public static boolean isConnectedBluetoothDevice( - CachedBluetoothDevice cachedDevice, AudioManager audioManager) { - int audioMode = audioManager.getMode(); + CachedBluetoothDevice cachedDevice, boolean isOngoingCall) { int currentAudioProfile; - if (audioMode == AudioManager.MODE_RINGTONE - || audioMode == AudioManager.MODE_IN_CALL - || audioMode == AudioManager.MODE_IN_COMMUNICATION) { - // in phone call + if (isOngoingCall) { currentAudioProfile = BluetoothProfile.HEADSET; } else { - // without phone call currentAudioProfile = BluetoothProfile.A2DP; } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java index 572444edea29..bf86911ee683 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java @@ -30,13 +30,11 @@ import android.util.Log; import androidx.annotation.ChecksSdkIntAtLeast; import com.android.internal.annotations.VisibleForTesting; -import com.android.settingslib.flags.Flags; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -387,7 +385,7 @@ public class CsipDeviceManager { preferredMainDevice.refresh(); hasChanged = true; } - syncAudioSharingStatusIfNeeded(preferredMainDevice); + syncAudioSharingSourceIfNeeded(preferredMainDevice); } if (hasChanged) { log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: " @@ -401,16 +399,13 @@ public class CsipDeviceManager { return userManager != null && userManager.isManagedProfile(); } - private void syncAudioSharingStatusIfNeeded(CachedBluetoothDevice mainDevice) { + private void syncAudioSharingSourceIfNeeded(CachedBluetoothDevice mainDevice) { boolean isAudioSharingEnabled = BluetoothUtils.isAudioSharingUIAvailable(mContext); - if (isAudioSharingEnabled && mainDevice != null) { + if (isAudioSharingEnabled) { if (isWorkProfile()) { - log("addMemberDevicesIntoMainDevice: skip sync audio sharing status, work profile"); + log("addMemberDevicesIntoMainDevice: skip sync source for work profile"); return; } - Set<CachedBluetoothDevice> deviceSet = new HashSet<>(); - deviceSet.add(mainDevice); - deviceSet.addAll(mainDevice.getMemberDevice()); boolean hasBroadcastSource = BluetoothUtils.isBroadcasting(mBtManager) && BluetoothUtils.hasConnectedBroadcastSource( mainDevice, mBtManager); @@ -424,6 +419,9 @@ public class CsipDeviceManager { if (metadata != null && assistant != null) { log("addMemberDevicesIntoMainDevice: sync audio sharing source after " + "combining the top level devices."); + Set<CachedBluetoothDevice> deviceSet = new HashSet<>(); + deviceSet.add(mainDevice); + deviceSet.addAll(mainDevice.getMemberDevice()); Set<BluetoothDevice> sinksToSync = deviceSet.stream() .map(CachedBluetoothDevice::getDevice) .filter(device -> @@ -437,24 +435,8 @@ public class CsipDeviceManager { } } } - if (Flags.enableTemporaryBondDevicesUi()) { - log("addMemberDevicesIntoMainDevice: sync temp bond metadata for audio sharing " - + "sinks after combining the top level devices."); - Set<BluetoothDevice> sinksToSync = deviceSet.stream() - .map(CachedBluetoothDevice::getDevice).filter(Objects::nonNull).collect( - Collectors.toSet()); - if (sinksToSync.stream().anyMatch(BluetoothUtils::isTemporaryBondDevice)) { - for (BluetoothDevice device : sinksToSync) { - if (!BluetoothUtils.isTemporaryBondDevice(device)) { - log("addMemberDevicesIntoMainDevice: sync temp bond metadata for " - + device.getAnonymizedAddress()); - BluetoothUtils.setTemporaryBondMetadata(device); - } - } - } - } } else { - log("addMemberDevicesIntoMainDevice: skip sync audio sharing status, flag disabled"); + log("addMemberDevicesIntoMainDevice: skip sync source, flag disabled"); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java index 84156429809b..367e38ed779d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java @@ -63,13 +63,14 @@ import com.google.common.collect.ImmutableList; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -84,6 +85,8 @@ import java.util.stream.Collectors; public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { public static final String ACTION_LE_AUDIO_SHARING_STATE_CHANGE = "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE"; + public static final String ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED = + "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_DEVICE_CONNECTED"; public static final String EXTRA_LE_AUDIO_SHARING_STATE = "BLUETOOTH_LE_AUDIO_SHARING_STATE"; public static final String EXTRA_BLUETOOTH_DEVICE = "BLUETOOTH_DEVICE"; public static final String EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE = "BT_DEVICE_TO_AUTO_ADD_SOURCE"; @@ -105,6 +108,10 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { private static final String SYSUI_PKG = "com.android.systemui"; private static final String TAG = "LocalBluetoothLeBroadcast"; private static final boolean DEBUG = BluetoothUtils.D; + private static final String VALID_PASSWORD_CHARACTERS = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+[]{}|;:," + + ".<>?/"; + private static final int PASSWORD_LENGTH = 16; static final String NAME = "LE_AUDIO_BROADCAST"; private static final String UNDERLINE = "_"; @@ -1085,11 +1092,16 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { mBroadcastId = UNKNOWN_VALUE_PLACEHOLDER; } - private String generateRandomPassword() { - String randomUUID = UUID.randomUUID().toString(); - // first 16 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx - return randomUUID.substring(0, 8) + randomUUID.substring(9, 13) + randomUUID.substring(14, - 18); + private static String generateRandomPassword() { + SecureRandom random = new SecureRandom(); + StringBuilder stringBuilder = new StringBuilder(PASSWORD_LENGTH); + + for (int i = 0; i < PASSWORD_LENGTH; i++) { + int randomIndex = random.nextInt(VALID_PASSWORD_CHARACTERS.length()); + stringBuilder.append(VALID_PASSWORD_CHARACTERS.charAt(randomIndex)); + } + + return stringBuilder.toString(); } private void registerContentObserver() { @@ -1189,6 +1201,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { @NonNull private Map<Integer, List<BluetoothDevice>> getDeviceGroupsInBroadcast() { + if (mServiceBroadcastAssistant == null) return new HashMap<>(); boolean hysteresisModeFixEnabled = BluetoothUtils.isAudioSharingHysteresisModeFixAvailable(mContext); List<BluetoothDevice> connectedDevices = mServiceBroadcastAssistant.getConnectedDevices(); diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java index 58e9355800d7..985599c952d1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java @@ -57,7 +57,7 @@ public class DisplayDensityUtils { * Summaries for scales smaller than "default" in order of smallest to * largest. */ - private static final int[] SUMMARIES_SMALLER = new int[] { + private static final int[] SUMMARIES_SMALLER = new int[]{ R.string.screen_zoom_summary_small }; @@ -65,7 +65,7 @@ public class DisplayDensityUtils { * Summaries for scales larger than "default" in order of smallest to * largest. */ - private static final int[] SUMMARIES_LARGER = new int[] { + private static final int[] SUMMARIES_LARGER = new int[]{ R.string.screen_zoom_summary_large, R.string.screen_zoom_summary_very_large, R.string.screen_zoom_summary_extremely_large, @@ -108,7 +108,8 @@ public class DisplayDensityUtils { * Creates an instance that stores the density values for the smallest display that satisfies * the predicate. It is enough to store the values for one display because the same density * should be set to all the displays that satisfy the predicate. - * @param context The context + * + * @param context The context * @param predicate Determines what displays the density should be set for. The default display * must satisfy this predicate. */ @@ -127,14 +128,10 @@ public class DisplayDensityUtils { mCurrentIndex = -1; return; } - if (!mPredicate.test(defaultDisplayInfo)) { - throw new IllegalArgumentException( - "Predicate must not filter out the default display."); - } - int idOfSmallestDisplay = Display.DEFAULT_DISPLAY; - int minDimensionPx = Math.min(defaultDisplayInfo.logicalWidth, - defaultDisplayInfo.logicalHeight); + int idOfSmallestDisplay = Display.INVALID_DISPLAY; + int minDimensionPx = Integer.MAX_VALUE; + DisplayInfo smallestDisplayInfo = null; for (Display display : mDisplayManager.getDisplays( DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) { DisplayInfo info = new DisplayInfo(); @@ -149,9 +146,19 @@ public class DisplayDensityUtils { if (minDimension < minDimensionPx) { minDimensionPx = minDimension; idOfSmallestDisplay = display.getDisplayId(); + smallestDisplayInfo = info; } } + if (smallestDisplayInfo == null) { + Log.w(LOG_TAG, "No display satisfies the predicate"); + mEntries = null; + mValues = null; + mDefaultDensity = 0; + mCurrentIndex = -1; + return; + } + final int defaultDensity = DisplayDensityUtils.getDefaultDensityForDisplay(idOfSmallestDisplay); if (defaultDensity <= 0) { @@ -165,7 +172,12 @@ public class DisplayDensityUtils { final Resources res = context.getResources(); - final int currentDensity = defaultDisplayInfo.logicalDensityDpi; + int currentDensity; + if (mPredicate.test(defaultDisplayInfo)) { + currentDensity = defaultDisplayInfo.logicalDensityDpi; + } else { + currentDensity = smallestDisplayInfo.logicalDensityDpi; + } int currentDensityIndex = -1; // Compute number of "larger" and "smaller" scales for this display. @@ -266,16 +278,16 @@ public class DisplayDensityUtils { * Returns the default density for the specified display. * * @param displayId the identifier of the display - * @return the default density of the specified display, or {@code -1} if - * the display does not exist or the density could not be obtained + * @return the default density of the specified display, or {@code -1} if the display does not + * exist or the density could not be obtained */ private static int getDefaultDensityForDisplay(int displayId) { - try { - final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); - return wm.getInitialDisplayDensity(displayId); - } catch (RemoteException exc) { - return -1; - } + try { + final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + return wm.getInitialDisplayDensity(displayId); + } catch (RemoteException exc) { + return -1; + } } /** diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java index 51259e2f311d..e7887ed26cc3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java @@ -295,9 +295,9 @@ public class DreamBackend { @WhenToDream public int getWhenToDreamSetting() { return isActivatedOnDock() && isActivatedOnSleep() ? WHILE_CHARGING_OR_DOCKED - : isActivatedOnDock() ? WHILE_DOCKED - : isActivatedOnPostured() ? WHILE_POSTURED - : isActivatedOnSleep() ? WHILE_CHARGING + : isActivatedOnSleep() ? WHILE_CHARGING + : isActivatedOnDock() ? WHILE_DOCKED + : isActivatedOnPostured() ? WHILE_POSTURED : NEVER; } diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java index 094567c400a3..9ca46238c2ce 100644 --- a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java +++ b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java @@ -18,6 +18,7 @@ package com.android.settingslib.mobile; import com.android.settingslib.R; import com.android.settingslib.SignalIcon.MobileIconGroup; +import com.android.settingslib.flags.Flags; import java.util.HashMap; import java.util.Map; @@ -29,22 +30,47 @@ public class TelephonyIcons { //***** Data connection icons public static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode; - public static final int ICON_LTE = R.drawable.ic_lte_mobiledata; - public static final int ICON_LTE_PLUS = R.drawable.ic_lte_plus_mobiledata; - public static final int ICON_G = R.drawable.ic_g_mobiledata; - public static final int ICON_E = R.drawable.ic_e_mobiledata; - public static final int ICON_H = R.drawable.ic_h_mobiledata; - public static final int ICON_H_PLUS = R.drawable.ic_h_plus_mobiledata; - public static final int ICON_3G = R.drawable.ic_3g_mobiledata; - public static final int ICON_4G = R.drawable.ic_4g_mobiledata; - public static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata; - public static final int ICON_4G_LTE = R.drawable.ic_4g_lte_mobiledata; - public static final int ICON_4G_LTE_PLUS = R.drawable.ic_4g_lte_plus_mobiledata; - public static final int ICON_5G_E = R.drawable.ic_5g_e_mobiledata; - public static final int ICON_1X = R.drawable.ic_1x_mobiledata; - public static final int ICON_5G = R.drawable.ic_5g_mobiledata; - public static final int ICON_5G_PLUS = R.drawable.ic_5g_plus_mobiledata; - public static final int ICON_CWF = R.drawable.ic_carrier_wifi; + public static final int ICON_LTE = + flagged(R.drawable.ic_lte_mobiledata, R.drawable.ic_lte_mobiledata_updated); + public static final int ICON_LTE_PLUS = + flagged(R.drawable.ic_lte_plus_mobiledata, R.drawable.ic_lte_plus_mobiledata_updated); + public static final int ICON_G = + flagged(R.drawable.ic_g_mobiledata, R.drawable.ic_g_mobiledata_updated); + public static final int ICON_E = + flagged(R.drawable.ic_e_mobiledata, R.drawable.ic_e_mobiledata_updated); + public static final int ICON_H = + flagged(R.drawable.ic_h_mobiledata, R.drawable.ic_h_mobiledata_updated); + public static final int ICON_H_PLUS = + flagged(R.drawable.ic_h_plus_mobiledata, R.drawable.ic_h_plus_mobiledata_updated); + public static final int ICON_3G = + flagged(R.drawable.ic_3g_mobiledata, R.drawable.ic_3g_mobiledata_updated); + public static final int ICON_4G = + flagged(R.drawable.ic_4g_mobiledata, R.drawable.ic_4g_mobiledata_updated); + public static final int ICON_4G_PLUS = + flagged(R.drawable.ic_4g_plus_mobiledata, R.drawable.ic_4g_plus_mobiledata_updated); + public static final int ICON_4G_LTE = + flagged(R.drawable.ic_4g_lte_mobiledata, R.drawable.ic_4g_lte_mobiledata_updated); + public static final int ICON_4G_LTE_PLUS = + flagged(R.drawable.ic_4g_lte_plus_mobiledata, + R.drawable.ic_4g_lte_plus_mobiledata_updated); + public static final int ICON_5G_E = + flagged(R.drawable.ic_5g_e_mobiledata, R.drawable.ic_5g_e_mobiledata_updated); + public static final int ICON_1X = + flagged(R.drawable.ic_1x_mobiledata, R.drawable.ic_1x_mobiledata_updated); + public static final int ICON_5G = + flagged(R.drawable.ic_5g_mobiledata, R.drawable.ic_5g_mobiledata_updated); + public static final int ICON_5G_PLUS = + flagged(R.drawable.ic_5g_plus_mobiledata, R.drawable.ic_5g_plus_mobiledata_updated); + public static final int ICON_CWF = + flagged(R.drawable.ic_carrier_wifi, R.drawable.ic_carrier_wifi_updated); + + /** Make it slightly more obvious which resource we are using */ + private static int flagged(int oldIcon, int newIcon) { + if (Flags.newStatusBarIcons()) { + return newIcon; + } + return oldIcon; + } public static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup( "CARRIER_NETWORK_CHANGE", diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java index d5cfe55813ee..460c790174ab 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java @@ -35,6 +35,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.SuppressLint; import android.app.AutomaticZenRule; import android.app.NotificationManager; +import android.content.ComponentName; import android.content.Context; import android.net.Uri; import android.os.Parcel; @@ -117,6 +118,14 @@ public class ZenMode implements Parcelable { DISABLED_BY_OTHER } + /** + * Information about the owner of a {@link ZenMode}. {@link #packageName()} is + * {@link SystemZenRules#PACKAGE_ANDROID} if the mode is system-owned; it may also be + * {@code null}, but only as an artifact of very old modes. + */ + public record Owner(@Nullable String packageName, @Nullable ComponentName configurationActivity, + @Nullable ComponentName conditionProvider) { } + private final String mId; private final AutomaticZenRule mRule; private final Kind mKind; @@ -198,7 +207,7 @@ public class ZenMode implements Parcelable { } @NonNull - public AutomaticZenRule getRule() { + AutomaticZenRule getRule() { return mRule; } @@ -207,6 +216,10 @@ public class ZenMode implements Parcelable { return Strings.nullToEmpty(mRule.getName()); } + public void setName(@NonNull String name) { + mRule.setName(name); + } + @NonNull public Kind getKind() { return mKind; @@ -217,6 +230,17 @@ public class ZenMode implements Parcelable { return mStatus; } + @NonNull + public Owner getOwner() { + return new Owner(mRule.getPackageName(), mRule.getConfigurationActivity(), + mRule.getOwner()); + } + + @Nullable + public String getOwnerPackage() { + return getOwner().packageName(); + } + @AutomaticZenRule.Type public int getType() { return mRule.getType(); @@ -257,6 +281,26 @@ public class ZenMode implements Parcelable { } } + /** + * Returns the resource id of the icon for this mode. Note that this is the <em>stored</em> + * resource id, and thus can be different from the value in {@link #getIconKey()} -- in + * particular, for modes without a custom icon set, this method returns {@code 0} whereas + * {@link #getIconKey()} will return a default icon based on other mode properties. + * + * <p>Most callers are interested in {@link #getIconKey()}, unless they are editing the icon. + */ + public int getIconResId() { + return mRule.getIconResId(); + } + + /** + * Sets the resource id of the icon for this mode. + * @see #getIconResId() + */ + public void setIconResId(@DrawableRes int iconResId) { + mRule.setIconResId(iconResId); + } + /** Returns the interruption filter of the mode. */ @NotificationManager.InterruptionFilter public int getInterruptionFilter() { @@ -445,6 +489,10 @@ public class ZenMode implements Parcelable { return mStatus == Status.ENABLED_AND_ACTIVE; } + public boolean isManualInvocationAllowed() { + return mRule.isManualInvocationAllowed(); + } + public boolean isSystemOwned() { return SystemZenRules.PACKAGE_ANDROID.equals(mRule.getPackageName()); } diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java index f5776989917e..b67339bace67 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeDescriptions.java @@ -70,8 +70,7 @@ public final class ZenModeDescriptions { public String getTriggerDescriptionForAccessibility(@NonNull ZenMode mode) { // Only one special case: time-based schedules, where we want to use full day names. if (mode.isSystemOwned() && mode.getType() == TYPE_SCHEDULE_TIME) { - ZenModeConfig.ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId( - mode.getRule().getConditionId()); + ZenModeConfig.ScheduleInfo schedule = ZenModeSchedules.getTimeSchedule(mode); if (schedule != null) { String fullDaysSummary = SystemZenRules.getDaysOfWeekFull(mContext, schedule); if (fullDaysSummary != null) { diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeSchedules.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeSchedules.java new file mode 100644 index 000000000000..c981652f231d --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenModeSchedules.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.notification.modes; + +import android.service.notification.ZenModeConfig; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class ZenModeSchedules { + + /** + * Returns the {@link ZenModeConfig.ScheduleInfo} time schedule corresponding to the mode, or + * {@code null} if the mode is not time-schedule-based. + */ + @Nullable + public static ZenModeConfig.ScheduleInfo getTimeSchedule(@NonNull ZenMode mode) { + return ZenModeConfig.tryParseScheduleConditionId(mode.getRule().getConditionId()); + } + + /** + * Returns the {@link ZenModeConfig.EventInfo} calendar schedule corresponding to the mode, or + * {@code null} if the mode is not calendar-schedule-based. + */ + @Nullable + public static ZenModeConfig.EventInfo getCalendarSchedule(@NonNull ZenMode mode) { + return ZenModeConfig.tryParseEventConditionId(mode.getRule().getConditionId()); + } + + private ZenModeSchedules() { } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java new file mode 100644 index 000000000000..c5e6f60e3fa6 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserActivity.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.users; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settingslib.R; + + +public class CreateUserActivity extends Activity { + private static final String TAG = "CreateUserActivity"; + + public static final String EXTRA_USER_NAME = "new_user_name"; + public static final String EXTRA_IS_ADMIN = "is_admin"; + public static final String EXTRA_USER_ICON_PATH = "user_icon_path"; + private static final String DIALOG_STATE_KEY = "create_user_dialog_state"; + private static final String EXTRA_CAN_CREATE_ADMIN = "can_create_admin"; + private static final String EXTRA_FILE_AUTHORITY = "file_authority"; + + private CreateUserDialogController mCreateUserDialogController; + @VisibleForTesting + Dialog mSetupUserDialog; + + + /** + * Creates intent to start CreateUserActivity + */ + public static @NonNull Intent createIntentForStart(@NonNull Context context, + boolean canCreateAdminUser, @NonNull String fileAuth) { + Intent intent = new Intent(context, CreateUserActivity.class); + intent.putExtra(EXTRA_CAN_CREATE_ADMIN, canCreateAdminUser); + intent.putExtra(EXTRA_FILE_AUTHORITY, fileAuth); + return intent; + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Intent intent = getIntent(); + + mCreateUserDialogController = new CreateUserDialogController( + intent.getStringExtra(EXTRA_FILE_AUTHORITY)); + setContentView(R.layout.activity_create_new_user); + if (savedInstanceState != null) { + mCreateUserDialogController.onRestoreInstanceState(savedInstanceState); + } + mSetupUserDialog = createDialog(intent.getBooleanExtra(EXTRA_CAN_CREATE_ADMIN, false)); + mSetupUserDialog.show(); + } + + @Override + protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + Bundle savedDialogState = savedInstanceState.getBundle(DIALOG_STATE_KEY); + if (savedDialogState != null && mSetupUserDialog != null) { + mSetupUserDialog.onRestoreInstanceState(savedDialogState); + } + } + + private Dialog createDialog(boolean canCreateAdminUser) { + return mCreateUserDialogController.createDialog( + this, + this::startActivity, + canCreateAdminUser, + this::setSuccessResult, + this::cancel + ); + } + + @Override + public boolean onTouchEvent(@Nullable MotionEvent event) { + onBackInvoked(); + return super.onTouchEvent(event); + } + + private void onBackInvoked() { + if (mSetupUserDialog != null) { + mSetupUserDialog.dismiss(); + } + setResult(RESULT_CANCELED); + finish(); + } + + @VisibleForTesting + void setSuccessResult(String userName, Drawable userIcon, String path, Boolean isAdmin) { + Intent intent = new Intent(this, CreateUserActivity.class); + intent.putExtra(EXTRA_USER_NAME, userName); + intent.putExtra(EXTRA_IS_ADMIN, isAdmin); + intent.putExtra(EXTRA_USER_ICON_PATH, path); + + mSetupUserDialog.dismiss(); + setResult(RESULT_OK, intent); + finish(); + } + + @VisibleForTesting + void cancel() { + mSetupUserDialog.dismiss(); + setResult(RESULT_CANCELED); + finish(); + } + + @Override + protected void onSaveInstanceState(@NonNull Bundle outState) { + if (mSetupUserDialog != null && mSetupUserDialog.isShowing()) { + outState.putBundle(DIALOG_STATE_KEY, mSetupUserDialog.onSaveInstanceState()); + } + mCreateUserDialogController.onSaveInstanceState(outState); + super.onSaveInstanceState(outState); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + mCreateUserDialogController.onActivityResult(requestCode, resultCode, data); + } + + private void startActivity(Intent intent, int requestCode) { + startActivityForResult(intent, requestCode); + mCreateUserDialogController.startingActivityForResult(); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java index d71b337228f6..d9f1b632323c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java @@ -242,7 +242,7 @@ public class CreateUserDialogController { .setMessage(messageResId) .setNegativeButtonText(R.string.cancel) .setPositiveButtonText(R.string.next); - mCustomDialogHelper.requestFocusOnTitle(); + focus(); break; case GRANT_ADMIN_DIALOG: mEditUserInfoView.setVisibility(View.GONE); @@ -255,7 +255,7 @@ public class CreateUserDialogController { .setMessage(R.string.user_grant_admin_message) .setNegativeButtonText(R.string.back) .setPositiveButtonText(R.string.next); - mCustomDialogHelper.requestFocusOnTitle(); + focus(); if (mIsAdmin == null) { mCustomDialogHelper.setButtonEnabled(false); } @@ -267,7 +267,7 @@ public class CreateUserDialogController { .setTitle(R.string.user_info_settings_title) .setNegativeButtonText(R.string.back) .setPositiveButtonText(R.string.done); - mCustomDialogHelper.requestFocusOnTitle(); + focus(); mEditUserInfoView.setVisibility(View.VISIBLE); mGrantAdminView.setVisibility(View.GONE); break; @@ -282,7 +282,7 @@ public class CreateUserDialogController { mCustomDialogHelper.getDialog().dismiss(); break; case EXIT_DIALOG: - mCustomDialogHelper.getDialog().dismiss(); + finish(); break; default: if (mCurrentState < EXIT_DIALOG) { @@ -394,13 +394,21 @@ public class CreateUserDialogController { return mCustomDialogHelper != null && mCustomDialogHelper.getDialog() != null; } + void focus() { + mCustomDialogHelper.requestFocusOnTitle(); + } + /** * Runs callback and clears saved values after dialog is dismissed. */ public void finish() { if (mCurrentState == CREATE_USER_AND_CLOSE) { if (mSuccessCallback != null) { - mSuccessCallback.onSuccess(mUserName, mNewUserIcon, Boolean.TRUE.equals(mIsAdmin)); + if (mEditUserPhotoController != null && mCachedDrawablePath == null) { + mCachedDrawablePath = mEditUserPhotoController.getCachedDrawablePath(); + } + mSuccessCallback.onSuccess(mUserName, mNewUserIcon, mCachedDrawablePath, + Boolean.TRUE.equals(mIsAdmin)); } } else { if (mCancelCallback != null) { diff --git a/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java b/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java index 3d18b59258b3..eed608e98cc9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/NewUserData.java @@ -18,6 +18,8 @@ package com.android.settingslib.users; import android.graphics.drawable.Drawable; +import androidx.annotation.Nullable; + /** * Defines a callback when a new user data is filled out. */ @@ -27,8 +29,10 @@ public interface NewUserData { * Consumes data relevant to new user that needs to be created. * @param userName New user name. * @param userImage New user icon. + * @param iconPath New user icon path. * @param isNewUserAdmin A boolean that indicated whether new user has admin status. */ - void onSuccess(String userName, Drawable userImage, Boolean isNewUserAdmin); + void onSuccess(@Nullable String userName, @Nullable Drawable userImage, + @Nullable String iconPath, @Nullable Boolean isNewUserAdmin); } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt index c71b19c9235f..88bccc9f6ebd 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt @@ -119,12 +119,16 @@ open class WifiUtils { private fun getIconsBasedOnFlag(): IntArray { return if (newStatusBarIcons()) { + // TODO(b/396664075): + // The new wifi icons only define a range of [0, 3]. Since this array is indexed on + // level, we can simulate the range squash by mapping both level 3 to drawn-level 2, + // and level 4 to drawn-level 3 intArrayOf( R.drawable.ic_wifi_0, R.drawable.ic_wifi_1, R.drawable.ic_wifi_2, + R.drawable.ic_wifi_2, R.drawable.ic_wifi_3, - R.drawable.ic_wifi_4 ) } else { intArrayOf( @@ -141,12 +145,13 @@ open class WifiUtils { private fun getErrorIconsBasedOnFlag(): IntArray { return if (newStatusBarIcons()) { + // See above note, new wifi icons only have 3 bars, so levels 2 and 3 are the same intArrayOf( R.drawable.ic_wifi_0_error, R.drawable.ic_wifi_1_error, R.drawable.ic_wifi_2_error, + R.drawable.ic_wifi_2_error, R.drawable.ic_wifi_3_error, - R.drawable.ic_wifi_4_error ) } else { intArrayOf( diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/display/DisplayDensityUtilsTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/display/DisplayDensityUtilsTest.java index bba278a0a661..73cf28f86e00 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/display/DisplayDensityUtilsTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/display/DisplayDensityUtilsTest.java @@ -88,8 +88,8 @@ public class DisplayDensityUtilsTest { @Test public void createDisplayDensityUtil_onlyDefaultDisplay() throws RemoteException { - var info = createDisplayInfoForDisplay(Display.DEFAULT_DISPLAY, Display.TYPE_INTERNAL, 2560, - 1600, 320); + var info = createDisplayInfoForDisplay( + Display.DEFAULT_DISPLAY, Display.TYPE_INTERNAL, 2560, 1600, 320); var display = new Display(mDisplayManagerGlobal, info.displayId, info, (DisplayAdjustments) null); doReturn(new Display[]{display}).when(mDisplayManager).getDisplays(any()); @@ -126,6 +126,33 @@ public class DisplayDensityUtilsTest { assertThat(mDisplayDensityUtils.getValues()).isEqualTo(new int[]{330, 390, 426, 462, 500}); } + @Test + public void createDisplayDensityUtil_forExternalDisplay() throws RemoteException { + // Default display + var defaultDisplayInfo = createDisplayInfoForDisplay(Display.DEFAULT_DISPLAY, + Display.TYPE_INTERNAL, 2000, 2000, 390); + var defaultDisplay = new Display(mDisplayManagerGlobal, defaultDisplayInfo.displayId, + defaultDisplayInfo, + (DisplayAdjustments) null); + doReturn(defaultDisplay).when(mDisplayManager).getDisplay(defaultDisplayInfo.displayId); + + // Create external display + var externalDisplayInfo = createDisplayInfoForDisplay(/* displayId= */ 2, + Display.TYPE_EXTERNAL, 1920, 1080, 85); + var externalDisplay = new Display(mDisplayManagerGlobal, externalDisplayInfo.displayId, + externalDisplayInfo, + (DisplayAdjustments) null); + + doReturn(new Display[]{externalDisplay, defaultDisplay}).when(mDisplayManager).getDisplays( + any()); + doReturn(externalDisplay).when(mDisplayManager).getDisplay(externalDisplayInfo.displayId); + + mDisplayDensityUtils = new DisplayDensityUtils(mContext, + (info) -> info.displayId == externalDisplayInfo.displayId); + + assertThat(mDisplayDensityUtils.getValues()).isEqualTo(new int[]{72, 85, 94, 102, 112}); + } + private DisplayInfo createDisplayInfoForDisplay(int displayId, int displayType, int width, int height, int density) throws RemoteException { var displayInfo = new DisplayInfo(); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java index 7c46db96595f..ebe6128e5582 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java @@ -87,7 +87,6 @@ public class BluetoothUtilsTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private BluetoothDevice mBluetoothDevice; - @Mock private AudioManager mAudioManager; @Mock private PackageManager mPackageManager; @Mock private LeAudioProfile mA2dpProfile; @Mock private LeAudioProfile mLeAudioProfile; @@ -446,13 +445,12 @@ public class BluetoothUtilsTest { assertThat( BluetoothUtils.isAvailableMediaBluetoothDevice( - mCachedBluetoothDevice, mAudioManager)) + mCachedBluetoothDevice, /* isOngoingCall= */ false)) .isTrue(); } @Test public void isAvailableMediaBluetoothDevice_isHeadset_isConnectedA2dpDevice_returnFalse() { - when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE); when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); @@ -460,13 +458,12 @@ public class BluetoothUtilsTest { assertThat( BluetoothUtils.isAvailableMediaBluetoothDevice( - mCachedBluetoothDevice, mAudioManager)) + mCachedBluetoothDevice, /* isOngoingCall= */ true)) .isFalse(); } @Test public void isAvailableMediaBluetoothDevice_isA2dp_isConnectedA2dpDevice_returnTrue() { - when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); @@ -474,13 +471,12 @@ public class BluetoothUtilsTest { assertThat( BluetoothUtils.isAvailableMediaBluetoothDevice( - mCachedBluetoothDevice, mAudioManager)) + mCachedBluetoothDevice, /* isOngoingCall= */ false)) .isTrue(); } @Test public void isAvailableMediaBluetoothDevice_isHeadset_isConnectedHfpDevice_returnTrue() { - when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE); when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); @@ -488,7 +484,7 @@ public class BluetoothUtilsTest { assertThat( BluetoothUtils.isAvailableMediaBluetoothDevice( - mCachedBluetoothDevice, mAudioManager)) + mCachedBluetoothDevice, /* isOngoingCall= */ true)) .isTrue(); } @@ -499,56 +495,52 @@ public class BluetoothUtilsTest { when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mBluetoothDevice.isConnected()).thenReturn(true); - assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager)) - .isFalse(); + assertThat(BluetoothUtils.isConnectedBluetoothDevice( + mCachedBluetoothDevice, /* isOngoingCall= */ false)).isFalse(); } @Test public void isConnectedBluetoothDevice_isHeadset_isConnectedA2dpDevice_returnTrue() { - when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE); when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mBluetoothDevice.isConnected()).thenReturn(true); - assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager)) - .isTrue(); + assertThat(BluetoothUtils.isConnectedBluetoothDevice( + mCachedBluetoothDevice, /* isOngoingCall= */ true)).isTrue(); } @Test public void isConnectedBluetoothDevice_isA2dp_isConnectedA2dpDevice_returnFalse() { - when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mBluetoothDevice.isConnected()).thenReturn(true); - assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager)) - .isFalse(); + assertThat(BluetoothUtils.isConnectedBluetoothDevice( + mCachedBluetoothDevice, /* isOngoingCall= */ false)).isFalse(); } @Test public void isConnectedBluetoothDevice_isHeadset_isConnectedHfpDevice_returnFalse() { - when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE); when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mBluetoothDevice.isConnected()).thenReturn(true); - assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager)) - .isFalse(); + assertThat(BluetoothUtils.isConnectedBluetoothDevice( + mCachedBluetoothDevice, /* isOngoingCall= */ true)).isFalse(); } @Test public void isConnectedBluetoothDevice_isNotConnected_returnFalse() { - when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_RINGTONE); when(mCachedBluetoothDevice.isConnectedA2dpDevice()).thenReturn(true); when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice); when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mBluetoothDevice.isConnected()).thenReturn(false); - assertThat(BluetoothUtils.isConnectedBluetoothDevice(mCachedBluetoothDevice, mAudioManager)) - .isFalse(); + assertThat(BluetoothUtils.isConnectedBluetoothDevice( + mCachedBluetoothDevice, /* isOngoingCall= */ true)).isFalse(); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java index 2eccaa626f3b..fd14d1ff6786 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CsipDeviceManagerTest.java @@ -40,8 +40,6 @@ import android.content.Context; import android.os.Looper; import android.os.Parcel; import android.os.UserManager; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import com.android.settingslib.flags.Flags; @@ -76,9 +74,6 @@ public class CsipDeviceManagerTest { private final static String DEVICE_ADDRESS_1 = "AA:BB:CC:DD:EE:11"; private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22"; private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33"; - private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25; - private static final String TEMP_BOND_METADATA = - "<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>"; private final static int GROUP1 = 1; private final BluetoothClass DEVICE_CLASS_1 = createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES); @@ -342,7 +337,6 @@ public class CsipDeviceManagerTest { } @Test - @DisableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING) public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_returnTrue() { // Condition: The preferredDevice is main and there is another main device in top list // Expected Result: return true and there is the preferredDevice in top list @@ -352,6 +346,7 @@ public class CsipDeviceManagerTest { mCachedDevices.add(preferredDevice); mCachedDevices.add(mCachedDevice2); mCachedDevices.add(mCachedDevice3); + mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice)) .isTrue(); @@ -364,7 +359,6 @@ public class CsipDeviceManagerTest { } @Test - @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI}) public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_workProfile_doNothing() { // Condition: The preferredDevice is main and there is another main device in top list @@ -375,6 +369,7 @@ public class CsipDeviceManagerTest { mCachedDevices.add(preferredDevice); mCachedDevices.add(mCachedDevice2); mCachedDevices.add(mCachedDevice3); + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); when(mBroadcast.isEnabled(null)).thenReturn(true); BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata); @@ -382,8 +377,6 @@ public class CsipDeviceManagerTest { BluetoothLeBroadcastReceiveState.class); when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L)); when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state)); - when(mDevice2.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS)) - .thenReturn(TEMP_BOND_METADATA.getBytes()); when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); when(mUserManager.isManagedProfile()).thenReturn(true); @@ -394,13 +387,10 @@ public class CsipDeviceManagerTest { assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue(); assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2); verify(mAssistant, never()).addSource(mDevice1, metadata, /* isGroupOp= */ false); - verify(mDevice1, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, - TEMP_BOND_METADATA.getBytes()); } @Test - @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI}) - public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncState() { + public void addMemberDevicesIntoMainDevice_preferredDeviceIsMainAndTwoMain_syncSource() { // Condition: The preferredDevice is main and there is another main device in top list // Expected Result: return true and there is the preferredDevice in top list CachedBluetoothDevice preferredDevice = mCachedDevice1; @@ -409,6 +399,7 @@ public class CsipDeviceManagerTest { mCachedDevices.add(preferredDevice); mCachedDevices.add(mCachedDevice2); mCachedDevices.add(mCachedDevice3); + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); when(mBroadcast.isEnabled(null)).thenReturn(true); BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata); @@ -416,8 +407,6 @@ public class CsipDeviceManagerTest { BluetoothLeBroadcastReceiveState.class); when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L)); when(mAssistant.getAllSources(mDevice2)).thenReturn(ImmutableList.of(state)); - when(mDevice2.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS)) - .thenReturn(TEMP_BOND_METADATA.getBytes()); assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice)) .isTrue(); @@ -426,8 +415,6 @@ public class CsipDeviceManagerTest { assertThat(mCachedDevices.contains(mCachedDevice3)).isTrue(); assertThat(preferredDevice.getMemberDevice()).contains(mCachedDevice2); verify(mAssistant).addSource(mDevice1, metadata, /* isGroupOp= */ false); - verify(mDevice1).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, - TEMP_BOND_METADATA.getBytes()); } @Test @@ -449,13 +436,13 @@ public class CsipDeviceManagerTest { } @Test - @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI}) public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_returnTrue() { // Condition: The preferredDevice is member and there are two main device in top list // Expected Result: return true and there is the preferredDevice in top list CachedBluetoothDevice preferredDevice = mCachedDevice2; BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice(); mCachedDevice3.setGroupId(GROUP1); + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); when(mBroadcast.isEnabled(null)).thenReturn(false); assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice)) @@ -470,20 +457,16 @@ public class CsipDeviceManagerTest { assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice); verify(mAssistant, never()).addSource(any(BluetoothDevice.class), any(BluetoothLeBroadcastMetadata.class), anyBoolean()); - verify(mDevice2, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, - TEMP_BOND_METADATA.getBytes()); - verify(mDevice3, never()).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, - TEMP_BOND_METADATA.getBytes()); } @Test - @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI}) - public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_syncState() { + public void addMemberDevicesIntoMainDevice_preferredDeviceIsMemberAndTwoMain_syncSource() { // Condition: The preferredDevice is member and there are two main device in top list // Expected Result: return true and there is the preferredDevice in top list CachedBluetoothDevice preferredDevice = mCachedDevice2; BluetoothDevice expectedMainBluetoothDevice = preferredDevice.getDevice(); mCachedDevice3.setGroupId(GROUP1); + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); when(mBroadcast.isEnabled(null)).thenReturn(true); BluetoothLeBroadcastMetadata metadata = Mockito.mock(BluetoothLeBroadcastMetadata.class); when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata); @@ -491,8 +474,6 @@ public class CsipDeviceManagerTest { BluetoothLeBroadcastReceiveState.class); when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L)); when(mAssistant.getAllSources(mDevice1)).thenReturn(ImmutableList.of(state)); - when(mDevice1.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS)) - .thenReturn(TEMP_BOND_METADATA.getBytes()); assertThat(mCsipDeviceManager.addMemberDevicesIntoMainDevice(GROUP1, preferredDevice)) .isTrue(); @@ -507,10 +488,6 @@ public class CsipDeviceManagerTest { assertThat(mCachedDevice1.getDevice()).isEqualTo(expectedMainBluetoothDevice); verify(mAssistant).addSource(mDevice2, metadata, /* isGroupOp= */ false); verify(mAssistant).addSource(mDevice3, metadata, /* isGroupOp= */ false); - verify(mDevice2).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, - TEMP_BOND_METADATA.getBytes()); - verify(mDevice3).setMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS, - TEMP_BOND_METADATA.getBytes()); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java index 00ae96cfab50..c21eb0ce777a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java @@ -16,6 +16,8 @@ package com.android.settingslib.dream; +import static android.service.dreams.Flags.FLAG_ALLOW_DREAM_WHEN_POSTURED; + import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_DATE; import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_HOME_CONTROLS; import static com.android.settingslib.dream.DreamBackend.COMPLICATION_TYPE_TIME; @@ -28,6 +30,7 @@ import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; +import android.platform.test.annotations.EnableFlags; import android.provider.Settings; import org.junit.After; @@ -173,6 +176,58 @@ public final class DreamBackendTest { .containsExactlyElementsIn(enabledComplications); } + @Test + @EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED) + public void testChargingAndPosturedBothEnabled() { + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + 1 + ); + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + 1 + ); + + assertThat(mBackend.getWhenToDreamSetting()).isEqualTo(DreamBackend.WHILE_CHARGING); + } + + @Test + public void testChargingAndDockedBothEnabled() { + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, + 1 + ); + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + 1 + ); + + assertThat(mBackend.getWhenToDreamSetting()).isEqualTo( + DreamBackend.WHILE_CHARGING_OR_DOCKED); + } + + @Test + @EnableFlags(FLAG_ALLOW_DREAM_WHEN_POSTURED) + public void testPosturedAndDockedBothEnabled() { + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_POSTURED, + 1 + ); + Settings.Secure.putInt( + mContext.getContentResolver(), + Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, + 1 + ); + + assertThat(mBackend.getWhenToDreamSetting()).isEqualTo( + DreamBackend.WHILE_DOCKED); + } + private void setControlsEnabledOnLockscreen(boolean enabled) { Settings.Secure.putInt( mContext.getContentResolver(), diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java index 6b30f159129e..71ecf5b76296 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/modes/ZenModeTest.java @@ -21,6 +21,7 @@ import static android.app.AutomaticZenRule.TYPE_DRIVING; import static android.app.AutomaticZenRule.TYPE_IMMERSIVE; import static android.app.AutomaticZenRule.TYPE_OTHER; import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR; +import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME; import static android.app.AutomaticZenRule.TYPE_THEATER; import static android.app.AutomaticZenRule.TYPE_UNKNOWN; import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS; @@ -35,6 +36,8 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; import android.app.AutomaticZenRule; +import android.content.ComponentName; +import android.content.Context; import android.net.Uri; import android.os.Parcel; import android.service.notification.Condition; @@ -43,13 +46,17 @@ import android.service.notification.ZenDeviceEffects; import android.service.notification.ZenModeConfig; import android.service.notification.ZenPolicy; +import androidx.test.core.app.ApplicationProvider; + import com.android.internal.R; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; @RunWith(RobolectricTestRunner.class) @@ -72,6 +79,13 @@ public class ZenModeTest { .setType(TYPE_OTHER) .build(); + private Context mContext; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + } + @Test public void testBasicMethods_mode() { ZenMode zenMode = new ZenMode("id", ZEN_RULE, zenConfigRuleFor(ZEN_RULE, true)); @@ -95,7 +109,7 @@ public class ZenModeTest { assertThat(manualMode.canEditPolicy()).isTrue(); assertThat(manualMode.canBeDeleted()).isFalse(); assertThat(manualMode.isActive()).isFalse(); - assertThat(manualMode.getRule().getPackageName()).isEqualTo(PACKAGE_ANDROID); + assertThat(manualMode.getOwnerPackage()).isEqualTo(PACKAGE_ANDROID); } @Test @@ -153,7 +167,7 @@ public class ZenModeTest { public void isCustomManual_scheduleTime_false() { AutomaticZenRule rule = new AutomaticZenRule.Builder("Mode", Uri.parse("x")) .setPackage(SystemZenRules.PACKAGE_ANDROID) - .setType(AutomaticZenRule.TYPE_SCHEDULE_TIME) + .setType(TYPE_SCHEDULE_TIME) .build(); ZenMode mode = new ZenMode("id", rule, zenConfigRuleFor(rule, false)); @@ -194,6 +208,23 @@ public class ZenModeTest { } @Test + public void getOwner_returnsOwnerDetails() { + AutomaticZenRule azr = new AutomaticZenRule.Builder("Rule", Uri.EMPTY) + .setPackage("package") + .setConfigurationActivity(new ComponentName("package", "configActivity")) + .setOwner(new ComponentName("package", "conditionService")) + .build(); + ZenMode zenMode = new ZenMode("id", azr, zenConfigRuleFor(azr, false)); + + ZenMode.Owner owner = zenMode.getOwner(); + assertThat(owner.packageName()).isEqualTo("package"); + assertThat(owner.configurationActivity()).isEqualTo( + new ComponentName("package", "configActivity")); + assertThat(owner.conditionProvider()).isEqualTo( + new ComponentName("package", "conditionService")); + } + + @Test public void getPolicy_interruptionFilterPriority_returnsZenPolicy() { AutomaticZenRule azr = new AutomaticZenRule.Builder("Rule", Uri.EMPTY) .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) @@ -245,7 +276,7 @@ public class ZenModeTest { zenMode.setPolicy(ZEN_POLICY); - assertThat(zenMode.getRule().getInterruptionFilter()).isEqualTo( + assertThat(zenMode.getInterruptionFilter()).isEqualTo( INTERRUPTION_FILTER_PRIORITY); assertThat(zenMode.getPolicy()).isEqualTo(ZEN_POLICY); assertThat(zenMode.getRule().getZenPolicy()).isEqualTo(ZEN_POLICY); @@ -397,6 +428,7 @@ public class ZenModeTest { assertThat(iconKey.resPackage()).isEqualTo("some.package"); assertThat(iconKey.resId()).isEqualTo(123); + assertThat(mode.getIconResId()).isEqualTo(123); } @Test @@ -411,6 +443,7 @@ public class ZenModeTest { assertThat(iconKey.resPackage()).isNull(); assertThat(iconKey.resId()).isEqualTo(123); + assertThat(mode.getIconResId()).isEqualTo(123); } @Test @@ -425,15 +458,18 @@ public class ZenModeTest { assertThat(iconKey.resPackage()).isEqualTo("some.package"); assertThat(iconKey.resId()).isEqualTo(123); + assertThat(mode.getIconResId()).isEqualTo(123); } @Test public void getIconKey_manualDnd_isDndIcon() { - ZenIcon.Key iconKey = TestModeBuilder.MANUAL_DND.getIconKey(); + ZenMode mode = TestModeBuilder.MANUAL_DND; + ZenIcon.Key iconKey = mode.getIconKey(); assertThat(iconKey.resPackage()).isNull(); assertThat(iconKey.resId()).isEqualTo( com.android.internal.R.drawable.ic_zen_mode_type_special_dnd); + assertThat(mode.getIconResId()).isEqualTo(0); } @Test @@ -448,6 +484,7 @@ public class ZenModeTest { assertThat(iconKey.resPackage()).isNull(); assertThat(iconKey.resId()).isEqualTo( com.android.internal.R.drawable.ic_zen_mode_type_bedtime); + assertThat(mode.getIconResId()).isEqualTo(0); } @Test @@ -462,6 +499,7 @@ public class ZenModeTest { assertThat(iconKey.resPackage()).isNull(); assertThat(iconKey.resId()).isEqualTo( com.android.internal.R.drawable.ic_zen_mode_type_schedule_calendar); + assertThat(mode.getIconResId()).isEqualTo(0); } @Test @@ -477,6 +515,77 @@ public class ZenModeTest { assertThat(iconKey.resPackage()).isNull(); assertThat(iconKey.resId()).isEqualTo( com.android.internal.R.drawable.ic_zen_mode_type_special_dnd); + assertThat(mode.getIconResId()).isEqualTo(0); + } + + @Test + public void setCustomModeConditionId_timeSchedule() { + ZenMode mode = new TestModeBuilder() + .setPackage(PACKAGE_ANDROID) + .build(); + ZenModeConfig.ScheduleInfo timeSchedule = new ZenModeConfig.ScheduleInfo(); + timeSchedule.startHour = 9; + timeSchedule.endHour = 12; + timeSchedule.days = new int[] {Calendar.SATURDAY, Calendar.SUNDAY}; + Uri scheduleUri = ZenModeConfig.toScheduleConditionId(timeSchedule); + + mode.setCustomModeConditionId(mContext, scheduleUri); + + assertThat(mode.getType()).isEqualTo(TYPE_SCHEDULE_TIME); + assertThat(ZenModeSchedules.getTimeSchedule(mode)).isEqualTo(timeSchedule); + assertThat(mode.getTriggerDescription()).isEqualTo("Sun, Sat, 9:00 AM - 12:00 PM"); + + assertThat(mode.getRule().getConditionId()).isEqualTo(scheduleUri); + assertThat(mode.getRule().getOwner()).isEqualTo( + ZenModeConfig.getScheduleConditionProvider()); + } + + @Test + public void setCustomModeConditionId_calendarSchedule() { + ZenMode mode = new TestModeBuilder() + .setPackage(PACKAGE_ANDROID) + .build(); + ZenModeConfig.EventInfo calendarSchedule = new ZenModeConfig.EventInfo(); + calendarSchedule.calendarId = 1L; + calendarSchedule.calName = "My events"; + Uri scheduleUri = ZenModeConfig.toEventConditionId(calendarSchedule); + + mode.setCustomModeConditionId(mContext, scheduleUri); + + assertThat(mode.getType()).isEqualTo(TYPE_SCHEDULE_CALENDAR); + assertThat(ZenModeSchedules.getCalendarSchedule(mode)).isEqualTo(calendarSchedule); + assertThat(mode.getTriggerDescription()).isEqualTo("My events"); + + assertThat(mode.getRule().getConditionId()).isEqualTo(scheduleUri); + assertThat(mode.getRule().getOwner()).isEqualTo( + ZenModeConfig.getEventConditionProvider()); + } + + @Test + public void setCustomModeConditionId_manualSchedule() { + ZenMode mode = new TestModeBuilder() + .setPackage(PACKAGE_ANDROID) + .build(); + + mode.setCustomModeConditionId(mContext, ZenModeConfig.toCustomManualConditionId()); + + assertThat(mode.getType()).isEqualTo(TYPE_OTHER); + assertThat(mode.getTriggerDescription()).isEqualTo(""); + + assertThat(mode.getRule().getConditionId()).isEqualTo( + ZenModeConfig.toCustomManualConditionId()); + assertThat(mode.getRule().getOwner()).isEqualTo( + ZenModeConfig.getCustomManualConditionProvider()); + } + + @Test + public void setCustomModeConditionId_nonSystemRule_throws() { + ZenMode mode = new TestModeBuilder() + .setPackage("some.other.package") + .build(); + + assertThrows(IllegalStateException.class, + () -> mode.setCustomModeConditionId(mContext, Uri.parse("blah"))); } private static void assertUnparceledIsEqualToOriginal(String type, ZenMode original) { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java new file mode 100644 index 000000000000..f58eb7cc2e31 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserActivityTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.users; + +import static com.android.settingslib.users.CreateUserActivity.EXTRA_IS_ADMIN; +import static com.android.settingslib.users.CreateUserActivity.EXTRA_USER_ICON_PATH; +import static com.android.settingslib.users.CreateUserActivity.EXTRA_USER_NAME; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.robolectric.Shadows.shadowOf; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.MotionEvent; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class CreateUserActivityTest { + + private static final String TEST_USER_NAME = "test_user"; + private static final String TEST_USER_ICON_PATH = "/test_path"; + private static final boolean TEST_IS_ADMIN = true; + + private Context mContext; + private CreateUserActivity mCreateUserActivity; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mCreateUserActivity = Robolectric.buildActivity(CreateUserActivity.class).setup().get(); + } + + @Test + public void startActivity_startsActivityForResult() { + Intent activityIntent = CreateUserActivity.createIntentForStart(mContext, true, ""); + mCreateUserActivity.startActivity(activityIntent, null); + + assertThat(shadowOf(mCreateUserActivity).getNextStartedActivityForResult().intent) + .isEqualTo(activityIntent); + } + + @Test + public void onTouchEvent_dismissesDialogAndCancelsResult() { + mCreateUserActivity.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, + 0)); + + assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse(); + assertThat(shadowOf(mCreateUserActivity).getResultCode()) + .isEqualTo(Activity.RESULT_CANCELED); + } + + @Test + public void setSuccessResult_dismissesDialogAndSetsSuccessResult() { + Drawable mockDrawable = mock(Drawable.class); + + mCreateUserActivity.setSuccessResult(TEST_USER_NAME, mockDrawable, TEST_USER_ICON_PATH, + TEST_IS_ADMIN); + + assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse(); + assertThat(shadowOf(mCreateUserActivity).getResultCode()).isEqualTo(Activity.RESULT_OK); + + Intent resultIntent = shadowOf(mCreateUserActivity).getResultIntent(); + assertThat(resultIntent.getStringExtra(EXTRA_USER_NAME)).isEqualTo(TEST_USER_NAME); + assertThat(resultIntent.getBooleanExtra(EXTRA_IS_ADMIN, false)).isEqualTo(TEST_IS_ADMIN); + assertThat(resultIntent.getStringExtra(EXTRA_USER_ICON_PATH)) + .isEqualTo(TEST_USER_ICON_PATH); + } + + @Test + public void cancel_dismissesDialogAndSetsCancelResult() { + mCreateUserActivity.cancel(); + + assertThat(mCreateUserActivity.mSetupUserDialog.isShowing()).isFalse(); + assertThat(shadowOf(mCreateUserActivity).getResultCode()) + .isEqualTo(Activity.RESULT_CANCELED); + } + + @Test + public void onSaveInstanceState_savesDialogState() { + Bundle outState = new Bundle(); + mCreateUserActivity.onSaveInstanceState(outState); + + CreateUserActivity restoredActivity = + Robolectric.buildActivity(CreateUserActivity.class).setup(outState).get(); + + assertThat(restoredActivity.mSetupUserDialog).isNotNull(); + assertThat(restoredActivity.mSetupUserDialog.isShowing()).isTrue(); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java index 68312223b4b1..e60232339e4c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/CreateUserDialogControllerTest.java @@ -211,7 +211,7 @@ public class CreateUserDialogControllerTest { editText.setText(expectedNewName); next.performClick(); verify(successCallback, times(1)) - .onSuccess(expectedNewName, null, true); + .onSuccess(expectedNewName, null, null, true); verifyNoInteractions(cancelCallback); } @@ -233,7 +233,7 @@ public class CreateUserDialogControllerTest { editText.setText(expectedNewName); next.performClick(); verify(successCallback, times(1)) - .onSuccess(expectedNewName, null, false); + .onSuccess(expectedNewName, null, null, false); verifyNoInteractions(cancelCallback); } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 95059779ce3d..f03a5fb454fa 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1696,6 +1696,7 @@ class SettingsProtoDumpUtil { proto.write(SettingProto.DEFAULT_VALUE, setting.getDefaultValue()); proto.write(SettingProto.DEFAULT_FROM_SYSTEM, setting.isDefaultFromSystem()); } + proto.write(SettingProto.PRESERVED_IN_RESTORE, setting.isValuePreservedInRestore()); proto.end(settingsToken); } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 7c588b3834a5..bc281eea39d8 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -988,6 +988,11 @@ public class SettingsProvider extends ContentProvider { if (setting.getTag() != null) { pw.print(" tag:"); pw.print(setting.getTag()); } + // The majority of settings are preserved in restore, so we're just dumping those that + // are not (to save space). + if (!setting.isValuePreservedInRestore()) { + pw.println(" notPreservedInRestore"); + } pw.println(); } } @@ -1498,7 +1503,7 @@ public class SettingsProvider extends ContentProvider { if (DEBUG) { Slog.v(LOG_TAG, "insertGlobalSetting(" + name + ", " + value + ", " + ", " + tag + ", " + makeDefault + ", " + requestingUserId - + ", " + forceNotify + ")"); + + ", " + forceNotify + ", " + overrideableByRestore + ")"); } return mutateGlobalSetting(name, value, tag, makeDefault, requestingUserId, MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore); @@ -1780,7 +1785,7 @@ public class SettingsProvider extends ContentProvider { if (DEBUG) { Slog.v(LOG_TAG, "insertSecureSetting(" + name + ", " + value + ", " + ", " + tag + ", " + makeDefault + ", " + requestingUserId - + ", " + forceNotify + ")"); + + ", " + forceNotify + ", " + overrideableByRestore + ")"); } return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId, MUTATION_OPERATION_INSERT, forceNotify, 0, overrideableByRestore); @@ -1941,7 +1946,7 @@ public class SettingsProvider extends ContentProvider { boolean overrideableByRestore) { if (DEBUG) { Slog.v(LOG_TAG, "insertSystemSetting(" + name + ", " + value + ", " - + requestingUserId + ")"); + + requestingUserId + ", " + overrideableByRestore + ")"); } return mutateSystemSetting(name, value, /* tag= */ null, requestingUserId, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java index 17ebf6fc3235..0484defeb4d7 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java @@ -30,6 +30,7 @@ import android.os.ShellCommand; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.util.Slog; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -94,6 +95,8 @@ final public class SettingsService extends Binder { } final static class MyShellCommand extends ShellCommand { + private static final String LOG_TAG = "SettingsShellCmd"; + final SettingsProvider mProvider; final boolean mDumping; @@ -115,6 +118,7 @@ final public class SettingsService extends Binder { String mTag = null; int mResetMode = -1; boolean mMakeDefault; + boolean mOverrideableByRestore; MyShellCommand(SettingsProvider provider, boolean dumping) { mProvider = provider; @@ -209,6 +213,7 @@ final public class SettingsService extends Binder { return -1; } break; + // At this point, mVerb == PUT } else if (mKey == null) { mKey = arg; // keep going; there's another PUT arg @@ -217,36 +222,8 @@ final public class SettingsService extends Binder { // what we have so far is a valid command valid = true; // keep going; there may be another PUT arg - } else if (mTag == null) { - mTag = arg; - if ("default".equalsIgnoreCase(mTag)) { - mTag = null; - mMakeDefault = true; - if (peekNextArg() == null) { - valid = true; - } else { - perr.println("Too many arguments"); - return -1; - } - break; - } - if (peekNextArg() == null) { - valid = true; - break; - } - } else { // PUT, final arg - if (!"default".equalsIgnoreCase(arg)) { - perr.println("Argument expected to be 'default'"); - return -1; - } - mMakeDefault = true; - if (peekNextArg() == null) { - valid = true; - } else { - perr.println("Too many arguments"); - return -1; - } - break; + } else { + valid = parseOptionalPutArgument(arg); } } while ((arg = getNextArg()) != null); @@ -275,7 +252,8 @@ final public class SettingsService extends Binder { pout.println(getForUser(iprovider, mUser, mTable, mKey)); break; case PUT: - putForUser(iprovider, mUser, mTable, mKey, mValue, mTag, mMakeDefault); + putForUser(iprovider, mUser, mTable, mKey, mValue, mTag, mMakeDefault, + mOverrideableByRestore); break; case DELETE: pout.println("Deleted " @@ -297,6 +275,41 @@ final public class SettingsService extends Binder { return 0; } + private boolean parseOptionalPutArgument(String arg) { + boolean valid = true; + // Given that the order is TAG default overrideableByRestore, we need to parse from the + // opposite direction + switch (arg) { + case "overrideableByRestore": + if (mOverrideableByRestore) { + valid = false; + } else { + mOverrideableByRestore = true; + } + break; + case "default": + if (mMakeDefault || mOverrideableByRestore) { + valid = false; + } else { + mMakeDefault = true; + } + break; + default: // tag + if (mMakeDefault || mOverrideableByRestore || mTag != null) { + valid = false; + } else { + mTag = arg; + } + break; + } + if (!valid) { + Slog.e(LOG_TAG, "parseOptionalPutArgument(" + arg + "): invalid state (" + + "mTag=" + mTag + ", mMakeDefault=" + mMakeDefault + + ", mOverrideableByRestore=" + mOverrideableByRestore + ")"); + } + return valid; + } + List<String> listForUser(IContentProvider provider, int userHandle, String table) { final String callListCommand; if ("system".equals(table)) callListCommand = Settings.CALL_METHOD_LIST_SYSTEM; @@ -351,7 +364,11 @@ final public class SettingsService extends Binder { } void putForUser(IContentProvider provider, int userHandle, final String table, - final String key, final String value, String tag, boolean makeDefault) { + final String key, final String value, String tag, boolean makeDefault, + boolean overrideableByRestore) { + Slog.v(LOG_TAG, "putForUser(userId=" + userHandle + ", table=" + table + ", key=" + key + + ", value=" + value + ", tag=" + tag + ", makeDefault=" + makeDefault + + ", overrideableByRestore=" + overrideableByRestore + ")"); final String callPutCommand; if ("system".equals(table)) { callPutCommand = Settings.CALL_METHOD_PUT_SYSTEM; @@ -377,6 +394,9 @@ final public class SettingsService extends Binder { if (makeDefault) { arg.putBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY, true); } + if (overrideableByRestore) { + arg.putBoolean(Settings.CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY, true); + } final AttributionSource attributionSource = new AttributionSource( Binder.getCallingUid(), resolveCallingPackage(), /*attributionTag*/ null); provider.call(attributionSource, Settings.AUTHORITY, @@ -474,10 +494,11 @@ final public class SettingsService extends Binder { pw.println(" Print this help text."); pw.println(" get [--user <USER_ID> | current] NAMESPACE KEY"); pw.println(" Retrieve the current value of KEY."); - pw.println(" put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TAG] [default]"); + pw.println(" put [--user <USER_ID> | current] NAMESPACE KEY VALUE [TAG] [default] [overrideableByRestore]"); pw.println(" Change the contents of KEY to VALUE."); - pw.println(" TAG to associate with the setting."); + pw.println(" TAG to associate with the setting (cannot be default or overrideableByRestore)."); pw.println(" {default} to set as the default, case-insensitive only for global/secure namespace"); + pw.println(" {overrideableByRestore} to let the value be overridden by BackupManager on restore operations"); pw.println(" delete [--user <USER_ID> | current] NAMESPACE KEY"); pw.println(" Delete the entry for KEY."); pw.println(" reset [--user <USER_ID> | current] NAMESPACE {PACKAGE_NAME | RESET_MODE}"); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 85617bad1a91..70c042cb8eba 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -811,7 +811,7 @@ public class SettingsBackupTest { Settings.Secure.V_TO_U_RESTORE_ALLOWLIST, Settings.Secure.V_TO_U_RESTORE_DENYLIST, Settings.Secure.REDACT_OTP_NOTIFICATION_WHILE_CONNECTED_TO_WIFI, - Settings.Secure.REDACT_OTP_NOTIFICATION_IMMEDIATELY); + Settings.Secure.OTP_NOTIFICATION_REDACTION_LOCK_TIME); @Test public void systemSettingsBackedUpOrDenied() { diff --git a/packages/SoundPicker/res/values-fr/strings.xml b/packages/SoundPicker/res/values-fr/strings.xml index 9452e70ff8df..bfcbc6749a83 100644 --- a/packages/SoundPicker/res/values-fr/strings.xml +++ b/packages/SoundPicker/res/values-fr/strings.xml @@ -18,7 +18,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="ringtone_default" msgid="798836092118824500">"Sonnerie par défaut"</string> <string name="notification_sound_default" msgid="8133121186242636840">"Son de notification par défaut"</string> - <string name="alarm_sound_default" msgid="4787646764557462649">"Son de l\'alarme par défaut"</string> + <string name="alarm_sound_default" msgid="4787646764557462649">"Son par défaut de l\'alarme"</string> <string name="add_ringtone_text" msgid="6642389991738337529">"Ajouter une sonnerie"</string> <string name="add_alarm_text" msgid="3545497316166999225">"Ajouter une alarme"</string> <string name="add_notification_text" msgid="4431129543300614788">"Ajouter une notification"</string> diff --git a/packages/SoundPicker/res/values-mr/strings.xml b/packages/SoundPicker/res/values-mr/strings.xml index 3ddb99114e3a..39c7c4b20ee9 100644 --- a/packages/SoundPicker/res/values-mr/strings.xml +++ b/packages/SoundPicker/res/values-mr/strings.xml @@ -17,7 +17,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="ringtone_default" msgid="798836092118824500">"डीफॉल्ट रिंगटोन"</string> - <string name="notification_sound_default" msgid="8133121186242636840">"डीफॉल्ट सूचना आवाज"</string> + <string name="notification_sound_default" msgid="8133121186242636840">"डीफॉल्ट नोटिफिकेशन आवाज"</string> <string name="alarm_sound_default" msgid="4787646764557462649">"डीफॉल्ट अलार्म आवाज"</string> <string name="add_ringtone_text" msgid="6642389991738337529">"रिंगटोन जोडा"</string> <string name="add_alarm_text" msgid="3545497316166999225">"अलार्म जोडा"</string> diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 3e241bfe6447..eb5b22f6c82c 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -974,6 +974,26 @@ flag { } flag { + name: "use_notif_inflation_thread_for_footer" + namespace: "systemui" + description: "use the @NotifInflation thread for FooterView and EmptyShadeView inflation" + bug: "375320642" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "use_notif_inflation_thread_for_row" + namespace: "systemui" + description: "use the @NotifInflation thread for ExpandableNotificationRow inflation" + bug: "375320642" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "notify_power_manager_user_activity_background" namespace: "systemui" description: "Decide whether to notify the user activity to power manager in the background thread." @@ -1350,6 +1370,16 @@ flag { } flag { + name: "media_controls_a11y_colors" + namespace: "systemui" + description: "Color scheme updates for improved a11y" + bug: "378848399" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "output_switcher_redesign" namespace: "systemui" description: "Enables visual update for Media Output Switcher" @@ -1895,6 +1925,13 @@ flag { } flag { + name: "physical_notification_movement" + namespace: "systemui" + description: "Make notifications use physics based animations for movement" + bug: "393581344" +} + +flag { name: "glanceable_hub_direct_edit_mode" namespace: "systemui" description: "Invokes edit mode directly from long press in glanceable hub" @@ -1977,6 +2014,16 @@ flag { } flag { + name: "hardware_color_styles" + namespace: "systemui" + description: "Enables loading initial colors based ion hardware color" + bug: "347286986" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "shade_launch_accessibility" namespace: "systemui" description: "Intercept accessibility focus events for the Shade during launch animations to avoid stray TalkBack events." diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt index 444389fb26ea..fdb07bdbe7f3 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt @@ -155,7 +155,7 @@ constructor( /** [ViewTransitionToken] to be used for storing transitioning view in [transitionRegistry] */ private val transitionToken = if (Flags.decoupleViewControllerInAnimlib()) { - ViewTransitionToken(transitioningView::class.java) + transitionRegistry?.register(transitioningView) } else { null } @@ -164,7 +164,7 @@ constructor( private val ghostedView: View get() = if (Flags.decoupleViewControllerInAnimlib()) { - transitionRegistry?.getView(transitionToken!!) + transitionToken?.let { token -> transitionRegistry?.getView(token) } } else { _ghostedView }!! @@ -186,10 +186,6 @@ constructor( ) } - if (Flags.decoupleViewControllerInAnimlib()) { - transitionRegistry?.register(transitionToken!!, transitioningView) - } - /** Find the first view with a background in [view] and its children. */ fun findBackground(view: View): Drawable? { if (view.background != null) { diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt index af3ca87bf788..280d90de7ace 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/IViewTransitionRegistry.kt @@ -22,12 +22,12 @@ import android.view.View interface IViewTransitionRegistry { /** - * Registers the transitioning [view] mapped to a [token] + * Registers the transitioning [view] mapped to returned token * - * @param token The token corresponding to the transitioning view * @param view The view undergoing transition + * @return token mapped to the transitioning view */ - fun register(token: ViewTransitionToken, view: View) + fun register(view: View): ViewTransitionToken /** * Unregisters the transitioned view from its corresponding [token] diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt index 86c7f76c6bee..882ff3b61ba9 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewTransitionRegistry.kt @@ -22,21 +22,21 @@ import java.lang.ref.WeakReference /** * A registry to temporarily store the view being transitioned into a Dialog (using - * [DialogTransitionAnimator]) or an Activity (using [ActivityTransitionAnimator]) + * [DialogTransitionAnimator]) or an Activity (using [ActivityTransitionAnimator]). */ class ViewTransitionRegistry : IViewTransitionRegistry { /** * A map of a unique token to a WeakReference of the View being transitioned. WeakReference * ensures that Views are garbage collected whenever they become eligible and avoid any - * memory leaks + * memory leaks. */ - private val registry by lazy { mutableMapOf<ViewTransitionToken, WeakReference<View>>() } + private val registry by lazy { mutableMapOf<ViewTransitionToken, ViewTransitionInfo>() } /** * A [View.OnAttachStateChangeListener] to be attached to all views stored in the registry to * ensure that views (and their corresponding entry) is automatically removed when the view is - * detached from the Window + * detached from the Window. */ private val listener by lazy { object : View.OnAttachStateChangeListener { @@ -45,74 +45,121 @@ class ViewTransitionRegistry : IViewTransitionRegistry { } override fun onViewDetachedFromWindow(view: View) { - getViewToken(view)?.let { token -> unregister(token) } + // if view is detached from window, remove it from registry irrespective of number + // of reference held by clients/user of this registry + getViewToken(view)?.let { token -> remove(token) } } } } /** - * Creates an entry of a unique "token" mapped to "transitioning view" in the registry + * Creates an entry of a unique token mapped to transitioning [view] in the registry. * - * @param token unique token associated with the transitioning view * @param view view undergoing transitions + * @return unique token mapped to the view being registered */ - override fun register(token: ViewTransitionToken, view: View) { + override fun register(view: View): ViewTransitionToken { + // if view being registered is already present in the registry and has a unique token + // assigned to it, reuse that token + getViewToken(view)?.let { token -> + registry[token]?.let { info -> info.viewRefCount += 1 } + return token + } + // token embedded as a view tag enables to use a single listener for all views + val token = ViewTransitionToken(view::class.java) view.setTag(R.id.tag_view_transition_token, token) view.addOnAttachStateChangeListener(listener) - registry[token] = WeakReference(view) + registry[token] = ViewTransitionInfo(WeakReference(view)) onRegistryUpdate() + + return token } /** - * Removes the entry associated with the unique "token" in the registry + * Unregisters a view mapped to the unique [token] in the registry. This will either remove the + * entry entirely from registry (if the reference count of the associated view reached zero) or + * will decrement the reference count of the associated view in the registry. * * @param token unique token associated with the transitioning view */ override fun unregister(token: ViewTransitionToken) { - registry.remove(token)?.let { - it.get()?.let { view -> + registry[token]?.let { info -> + info.viewRefCount -= 1 + if (info.viewRefCount == 0) { + remove(token) + } + } + } + + /** + * Removes the entry associated with the unique [token] in the registry. + * + * @param token unique token associated with the transitioning view + */ + private fun remove(token: ViewTransitionToken) { + registry.remove(token)?.let { removedInfo -> + removedInfo.viewRef.get()?.let { view -> view.removeOnAttachStateChangeListener(listener) view.setTag(R.id.tag_view_transition_token, null) } - it.clear() + removedInfo.viewRef.clear() onRegistryUpdate() } } /** - * Access a view from registry using unique "token" associated with it + * Access a view from registry using unique [token] associated with it. * WARNING - this returns a StrongReference to the View stored in the registry */ override fun getView(token: ViewTransitionToken): View? { - return registry[token]?.get() + return registry[token]?.viewRef?.get() } /** - * Return token mapped to the [view], if it is present in the registry + * Return token mapped to the [view], if it is present in the registry. * * @param view the transitioning view whose token we are requesting * @return token associated with the [view] if present, else null */ override fun getViewToken(view: View): ViewTransitionToken? { - return (view.getTag(R.id.tag_view_transition_token) as? ViewTransitionToken)?.let { token -> - getView(token)?.let { token } + // extract token from the view if it is embedded inside it as a tag + val token = view.getTag(R.id.tag_view_transition_token) as? ViewTransitionToken + + // this should never really happen, but if token embedded inside the view as tag, doesn't + // point to a valid view in the registry, remove that token (tag) from the view and registry + if (token != null && getView(token) == null) { + view.setTag(R.id.tag_view_transition_token, null) + remove(token) + return null } + + return token } - /** Event call to run on registry update (on both [register] and [unregister]) */ + /** Event call to run on registry update (on both [register] and [unregister]). */ override fun onRegistryUpdate() { emitCountForTrace() } /** * Utility function to emit number of non-null views in the registry whenever the registry is - * updated (via [register] or [unregister]) + * updated (via [register] or [unregister]). */ private fun emitCountForTrace() { Trace.setCounter("transition_registry_view_count", registry.count().toLong()) } + /** Information associated with each transitioning view in the registry. */ + private data class ViewTransitionInfo( + + /** View being transitioned */ + val viewRef: WeakReference<View>, + + /** Count of clients (users of this registry) referencing same transitioning view */ + var viewRefCount: Int = 1 + ) + companion object { val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { ViewTransitionRegistry() } } diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt index 2a27a3033cf9..6eafb9f60b9e 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDetector.kt @@ -29,6 +29,14 @@ import com.intellij.psi.PsiParameter import org.jetbrains.uast.UClass import org.jetbrains.uast.getContainingUFile +/** + * Lint check to ensure that when including a Context or Context-dependent argument in + * shade-relevant packages, the argument has the @ShadeDisplayAware annotation. + * + * This is to ensure that Context-dependent components correctly handle Configuration changes when + * the shade is moved to a different display. @ShadeDisplayAware-annotated components will update + * accordingly to reflect the new display. + */ class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner { override fun getApplicableUastTypes() = listOf(UClass::class.java) @@ -38,8 +46,8 @@ class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner { for (constructor in node.constructors) { // Visit all injected constructors in shade-relevant packages if (!constructor.hasAnnotation(INJECT_ANNOTATION)) continue - if (!isInRelevantShadePackage(node)) continue - if (IGNORED_PACKAGES.contains(node.qualifiedName)) continue + if (!isInRelevantShadePackage(node.getContainingUFile()?.packageName)) continue + if (IGNORED_CLASSES.contains(node.qualifiedName)) continue for (parameter in constructor.parameterList.parameters) { if (parameter.shouldReport()) { @@ -84,24 +92,19 @@ class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner { CONFIG_INTERACTOR, ) - private val CONFIG_CLASSES = setOf(CONFIG_STATE, CONFIG_CONTROLLER, CONFIG_INTERACTOR) - private val SHADE_WINDOW_PACKAGES = listOf( "com.android.systemui.biometrics", "com.android.systemui.bouncer", "com.android.systemui.keyboard.docking.ui.viewmodel", + "com.android.systemui.media.controls.ui.controller", "com.android.systemui.qs", "com.android.systemui.shade", - "com.android.systemui.statusbar.notification", + "com.android.systemui.statusbar.lockscreen", "com.android.systemui.unfold.domain.interactor", ) - private val IGNORED_PACKAGES = - setOf( - "com.android.systemui.biometrics.UdfpsController", - "com.android.systemui.qs.customize.TileAdapter", - ) + private val IGNORED_CLASSES = setOf("com.android.systemui.statusbar.phone.SystemUIDialog") private fun PsiParameter.shouldReport(): Boolean { val className = type.canonicalText @@ -116,8 +119,7 @@ class ShadeDisplayAwareDetector : Detector(), SourceCodeScanner { return true } - private fun isInRelevantShadePackage(node: UClass): Boolean { - val packageName = node.getContainingUFile()?.packageName + fun isInRelevantShadePackage(packageName: String?): Boolean { if (packageName.isNullOrBlank()) return false return SHADE_WINDOW_PACKAGES.any { relevantPackage -> packageName.startsWith(relevantPackage) diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDialogDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDialogDetector.kt new file mode 100644 index 000000000000..4cd5d89ea919 --- /dev/null +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/ShadeDisplayAwareDialogDetector.kt @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.systemui.lint + +import com.android.internal.systemui.lint.ShadeDisplayAwareDetector.Companion.isInRelevantShadePackage +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import com.android.tools.lint.detector.api.SourceCodeScanner +import com.android.tools.lint.detector.api.UastLintUtils.Companion.tryResolveUDeclaration +import com.intellij.psi.PsiMethod +import org.jetbrains.uast.UCallExpression +import org.jetbrains.uast.getContainingUClass +import org.jetbrains.uast.getContainingUFile + +/** + * Lint check to ensure that when creating dialogs shade-relevant packages, the correct Context is + * provided. + * + * This is to ensure that the dialog is created with the correct context when the shade is moved to + * a different display. When the shade is moved, the configuration might change, and only + * `@ShadeDisplayAware`-annotated components will update accordingly to reflect the new display. + * + * Example: + * ```kotlin + * class ExampleClass + * @Inject + * constructor(private val contextInteractor: ShadeDialogContextInteractor) { + * + * fun showDialog() { + * val dialog = systemUIDialogFactory.create(delegate, contextInteractor.context) + * dialog.show() + * } + * } + * ``` + */ +// TODO: b/396066687 - update linter after refactoring to use ShadeDialogFactory +class ShadeDisplayAwareDialogDetector : Detector(), SourceCodeScanner { + override fun getApplicableMethodNames(): List<String> = listOf(CREATE_METHOD) + + override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { + if (!isInRelevantShadePackage(node.getContainingUFile()?.packageName)) return + if (!context.evaluator.isMemberInClass(method, SYSUI_DIALOG_FACTORY)) return + val contextArg = + node.valueArguments.find { + it.getExpressionType()?.canonicalText == "android.content.Context" + } + if (contextArg == null) { + context.report( + issue = ISSUE, + scope = node, + location = context.getNameLocation(node), + message = + "SystemUIDialog.Factory#create requires a Context that accounts for the " + + "shade's display. Use create(shadeDialogContextInteractor.getContext()) " + + "or create(shadeDialogContextInteractor.context) to provide the correct Context.", + ) + } else { + val isProvidedByContextInteractor = + contextArg.tryResolveUDeclaration()?.getContainingUClass()?.qualifiedName == + SHADE_DIALOG_CONTEXT_INTERACTOR + + if (!isProvidedByContextInteractor) { + context.report( + issue = ISSUE, + scope = contextArg, + location = context.getNameLocation(contextArg), + message = + "In shade-relevant packages, SystemUIDialog.Factory#create must be called " + + "with the Context directly from ShadeDialogContextInteractor " + + "(ShadeDialogContextInteractor.context or getContext()). " + + "Avoid intermediate variables or function calls. This direct usage " + + "is required to ensure proper shade display handling.", + ) + } + } + } + + companion object { + private const val CREATE_METHOD = "create" + private const val SYSUI_DIALOG_FACTORY = + "com.android.systemui.statusbar.phone.SystemUIDialog.Factory" + private const val SHADE_DIALOG_CONTEXT_INTERACTOR = + "com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor" + + @JvmField + val ISSUE: Issue = + Issue.create( + id = "ShadeDisplayAwareDialogChecker", + briefDescription = "Checking for shade display aware context when creating dialogs", + explanation = + """ + Dialogs created by the notification shade must use a special Context to appear + on the correct display, especially when the shade is not on the default display. + """ + .trimIndent(), + category = Category.CORRECTNESS, + priority = 8, + severity = Severity.WARNING, + implementation = + Implementation( + ShadeDisplayAwareDialogDetector::class.java, + Scope.JAVA_FILE_SCOPE, + ), + ) + } +} diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt index 6d18f9377806..adb311610587 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt @@ -47,6 +47,7 @@ class SystemUIIssueRegistry : IssueRegistry() { TestFunctionNameViolationDetector.ISSUE, MissingApacheLicenseDetector.ISSUE, ShadeDisplayAwareDetector.ISSUE, + ShadeDisplayAwareDialogDetector.ISSUE, RegisterContentObserverSyncViaSettingsProxyDetector.SYNC_WARNING, RegisterContentObserverViaContentResolverDetector.CONTENT_RESOLVER_ERROR, ) diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt index 638d7cb7ee58..f8f8b40c4c01 100644 --- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDetectorTest.kt @@ -410,34 +410,6 @@ class ShadeDisplayAwareDetectorTest : SystemUILintDetectorTest() { .expectClean() } - @Test - fun injectedConstructor_inExemptPackage_withRelevantParameter_withoutAnnotation() { - lint() - .files( - TestFiles.java( - """ - package com.android.systemui.qs.customize; - - import javax.inject.Inject; - import com.android.systemui.qs.dagger.QSThemedContext; - import android.content.Context; - - public class TileAdapter { - @Inject - public TileAdapter(@QSThemedContext Context context) {} - } - """ - .trimIndent() - ), - *androidStubs, - *otherStubs, - ) - .issues(ShadeDisplayAwareDetector.ISSUE) - .testModes(TestMode.DEFAULT) - .run() - .expectClean() - } - private fun errorMsgString(lineNumber: Int, className: String) = "src/com/android/systemui/shade/example/ExampleClass.kt:$lineNumber: Error: UI elements of " + "the shade window should use ShadeDisplayAware-annotated $className, as the shade " + diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDialogDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDialogDetectorTest.kt new file mode 100644 index 000000000000..86cdcdcf9644 --- /dev/null +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/ShadeDisplayAwareDialogDetectorTest.kt @@ -0,0 +1,541 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.systemui.lint + +import com.android.tools.lint.checks.infrastructure.TestFile +import com.android.tools.lint.checks.infrastructure.TestFiles +import com.android.tools.lint.checks.infrastructure.TestMode +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue +import org.junit.Test + +class ShadeDisplayAwareDialogDetectorTest : SystemUILintDetectorTest() { + override fun getDetector(): Detector = ShadeDisplayAwareDialogDetector() + + override fun getIssues(): List<Issue> = listOf(ShadeDisplayAwareDialogDetector.ISSUE) + + private val injectStub: TestFile = + kotlin( + """ + package javax.inject + @Retention(AnnotationRetention.RUNTIME) annotation class Inject + """ + ) + .indented() + private val shadeDisplayAwareStub: TestFile = + kotlin( + """ + package com.android.systemui.shade + @Retention(AnnotationRetention.RUNTIME) annotation class ShadeDisplayAware + """ + ) + .indented() + private val mainStub: TestFile = + kotlin( + """ + package com.android.systemui.dagger.qualifiers + + @Retention(AnnotationRetention.RUNTIME) annotation class Main + """ + ) + .indented() + private val dialogContextStub: TestFile = + kotlin( + """ + package com.android.systemui.shade.domain.interactor + + import android.content.Context + + interface ShadeDialogContextInteractor { + val context: Context + } + """ + ) + .indented() + private val delegateStub: TestFile = + java( + """ + package com.android.systemui.statusbar.phone; + + public interface Delegate { } + """ + .trimIndent() + ) + private val sysuiDialogStub: TestFile = + java( + """ + package com.android.systemui.statusbar.phone; + + import android.content.Context; + public class SystemUIDialog { + public SystemUIDialog(int id) { } + + public static class Factory { + public SystemUIDialog create() { + return new SystemUIDialog(); + } + + public SystemUIDialog create(Context context) { + return new SystemUIDialog(); + } + + public SystemUIDialog create(Delegate delegate, Context context) { + return new SystemUIDialog(); + } + + public SystemUIDialog create(Delegate delegate, Context context, + boolean shouldAcsdDismissDialog) { + return new SystemUIDialog(); + } + + public SystemUIDialog create(Delegate delegate, Context context, int theme) { + return new SystemUIDialog(); + } + + public SystemUIDialog create(Delegate delegate) { + return new SystemUIDialog(); + } + } + } + """ + ) + .indented() + + private val otherStubs = + arrayOf( + injectStub, + shadeDisplayAwareStub, + mainStub, + delegateStub, + sysuiDialogStub, + dialogContextStub, + ) + + @Test + fun create_noArguments() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import android.content.Context + import com.android.systemui.statusbar.phone.SystemUIDialog + + class ExampleClass + @Inject + constructor(private val systemUIDialogFactory: SystemUIDialog.Factory) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create() + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectWarningCount(1) + .expectContains( + "SystemUIDialog.Factory#create requires a Context that accounts for the " + + "shade's display. Use create(shadeDialogContextInteractor.getContext()) " + + "or create(shadeDialogContextInteractor.context) to provide the correct Context." + ) + .expectContains("[ShadeDisplayAwareDialogChecker]") + .expectContains("0 errors, 1 warning") + } + + @Test + fun create_UnannotatedContext() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import android.content.Context + import com.android.systemui.statusbar.phone.SystemUIDialog + class ExampleClass + @Inject + constructor( + private val context: Context, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create(context) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectWarningCount(1) + .expectContains( + "In shade-relevant packages, SystemUIDialog.Factory#create must be called " + + "with the Context directly from ShadeDialogContextInteractor " + + "(ShadeDialogContextInteractor.context or getContext()). " + + "Avoid intermediate variables or function calls. This direct usage " + + "is required to ensure proper shade display handling." + ) + .expectContains("[ShadeDisplayAwareDialogChecker]") + .expectContains("0 errors, 1 warning") + } + + @Test + fun create_annotatedContext() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import android.content.Context + import com.android.systemui.statusbar.phone.SystemUIDialog + import com.android.systemui.shade.ShadeDisplayAware + class ExampleClass + @Inject + constructor( + @ShadeDisplayAware private val context: Context, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create(context) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectWarningCount(1) + .expectContains( + "In shade-relevant packages, SystemUIDialog.Factory#create must be called " + + "with the Context directly from ShadeDialogContextInteractor " + + "(ShadeDialogContextInteractor.context or getContext()). " + + "Avoid intermediate variables or function calls. This direct usage " + + "is required to ensure proper shade display handling." + ) + .expectContains("[ShadeDisplayAwareDialogChecker]") + .expectContains("0 errors, 1 warning") + } + + @Test + fun create_LocalVariable() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import com.android.systemui.statusbar.phone.SystemUIDialog + import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor + + class ExampleClass + @Inject + constructor( + private val contextInteractor: ShadeDialogContextInteractor, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val context2 = contextInteractor.context + val dialog = systemUIDialogFactory.create(context2) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectWarningCount(1) + .expectContains( + "In shade-relevant packages, SystemUIDialog.Factory#create must be called " + + "with the Context directly from ShadeDialogContextInteractor " + + "(ShadeDialogContextInteractor.context or getContext()). " + + "Avoid intermediate variables or function calls. This direct usage " + + "is required to ensure proper shade display handling." + ) + .expectContains("[ShadeDisplayAwareDialogChecker]") + .expectContains("0 errors, 1 warning") + } + + @Test + fun create_delegate_UnannotatedContext() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import android.content.Context + import com.android.systemui.statusbar.phone.SystemUIDialog + import com.android.systemui.statusbar.phone.Delegate + class ExampleClass + @Inject + constructor( + private val context: Context, + private val delegate: Delegate, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create(delegate, context) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectWarningCount(1) + .expectContains( + "In shade-relevant packages, SystemUIDialog.Factory#create must be called " + + "with the Context directly from ShadeDialogContextInteractor " + + "(ShadeDialogContextInteractor.context or getContext()). " + + "Avoid intermediate variables or function calls. This direct usage " + + "is required to ensure proper shade display handling." + ) + .expectContains("[ShadeDisplayAwareDialogChecker]") + .expectContains("0 errors, 1 warning") + } + + @Test + fun create_delegate_Context() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import android.content.Context + import com.android.systemui.statusbar.phone.SystemUIDialog + import com.android.systemui.statusbar.phone.Delegate + import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor + + class ExampleClass + @Inject + constructor( + private val delegate: Delegate, + private val contextInteractor: ShadeDialogContextInteractor, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create(delegate, contextInteractor.context) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectClean() + } + + @Test + fun create_Delegate_Context_Boolean() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor + import com.android.systemui.statusbar.phone.SystemUIDialog + import com.android.systemui.statusbar.phone.Delegate + + class ExampleClass + @Inject + constructor( + private val delegate: Delegate, + private val contextInteractor: ShadeDialogContextInteractor, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create(delegate, contextInteractor.context, true) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectClean() + } + + @Test + fun create_Delegate_UnannotatedContext_Int() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import android.content.Context + import com.android.systemui.statusbar.phone.SystemUIDialog + import com.android.systemui.statusbar.phone.Delegate + class ExampleClass + @Inject + constructor( + private val context: Context, + private val delegate: Delegate, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create(delegate, context, 0) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectWarningCount(1) + .expectContains( + "In shade-relevant packages, SystemUIDialog.Factory#create must be called " + + "with the Context directly from ShadeDialogContextInteractor " + + "(ShadeDialogContextInteractor.context or getContext()). " + + "Avoid intermediate variables or function calls. This direct usage " + + "is required to ensure proper shade display handling." + ) + .expectContains("[ShadeDisplayAwareDialogChecker]") + .expectContains("0 errors, 1 warning") + } + + @Test + fun create_Delegate_Context_Int() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor + import com.android.systemui.statusbar.phone.SystemUIDialog + import com.android.systemui.statusbar.phone.Delegate + + class ExampleClass + @Inject + constructor( + private val delegate: Delegate, + private val contextInteractor: ShadeDialogContextInteractor, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create(delegate, contextInteractor.context, 0) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectClean() + } + + @Test + fun create_Delegate() { + lint() + .files( + TestFiles.kotlin( + """ + package com.android.systemui.shade.example + import javax.inject.Inject + import com.android.systemui.statusbar.phone.Delegate + import com.android.systemui.statusbar.phone.SystemUIDialog + + class ExampleClass + @Inject + constructor( + private val delegate: Delegate, + private val systemUIDialogFactory: SystemUIDialog.Factory + ) { + + fun showDialog() { + val dialog = systemUIDialogFactory.create(delegate) + dialog.show() + } + } + """ + .trimIndent() + ), + *androidStubs, + *otherStubs, + ) + .issues(ShadeDisplayAwareDialogDetector.ISSUE) + .testModes(TestMode.DEFAULT) + .run() + .expectWarningCount(1) + .expectContains( + "SystemUIDialog.Factory#create requires a Context that accounts for the " + + "shade's display. Use create(shadeDialogContextInteractor.getContext()) " + + "or create(shadeDialogContextInteractor.context) to provide the correct Context." + ) + .expectContains("[ShadeDisplayAwareDialogChecker]") + .expectContains("0 errors, 1 warning") + } +} diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt index ae75e6c089ca..873991923e51 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Expandable.kt @@ -31,15 +31,13 @@ import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.requiredSize import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.LocalContentColor import androidx.compose.material3.contentColorFor import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.State -import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.movableContentOf import androidx.compose.runtime.mutableStateOf @@ -63,9 +61,17 @@ import androidx.compose.ui.graphics.drawOutline import androidx.compose.ui.graphics.drawscope.ContentDrawScope import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.scale +import androidx.compose.ui.graphics.drawscope.translate +import androidx.compose.ui.graphics.layer.GraphicsLayer +import androidx.compose.ui.graphics.layer.drawLayer +import androidx.compose.ui.graphics.rememberGraphicsLayer import androidx.compose.ui.layout.boundsInRoot import androidx.compose.ui.layout.findRootCoordinates +import androidx.compose.ui.layout.layout import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.onPlaced +import androidx.compose.ui.node.DrawModifierNode +import androidx.compose.ui.node.ModifierNodeElement import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.Density @@ -76,6 +82,8 @@ import androidx.lifecycle.setViewTreeLifecycleOwner import androidx.lifecycle.setViewTreeViewModelStoreOwner import androidx.savedstate.findViewTreeSavedStateRegistryOwner import androidx.savedstate.setViewTreeSavedStateRegistryOwner +import com.android.compose.modifiers.thenIf +import com.android.compose.ui.graphics.FullScreenComposeViewInOverlay import com.android.systemui.animation.Expandable import com.android.systemui.animation.TransitionAnimator import kotlin.math.max @@ -123,6 +131,9 @@ fun Expandable( borderStroke: BorderStroke? = null, onClick: ((Expandable) -> Unit)? = null, interactionSource: MutableInteractionSource? = null, + // TODO(b/285250939): Default this to true then remove once the Compose QS expandables have + // proven that the new implementation is robust. + useModifierBasedImplementation: Boolean = false, content: @Composable (Expandable) -> Unit, ) { Expandable( @@ -130,6 +141,7 @@ fun Expandable( modifier, onClick, interactionSource, + useModifierBasedImplementation, content, ) } @@ -158,16 +170,26 @@ fun Expandable( * @sample com.android.systemui.compose.gallery.ActivityLaunchScreen * @sample com.android.systemui.compose.gallery.DialogLaunchScreen */ -@OptIn(ExperimentalMaterial3Api::class) @Composable fun Expandable( controller: ExpandableController, modifier: Modifier = Modifier, onClick: ((Expandable) -> Unit)? = null, interactionSource: MutableInteractionSource? = null, + // TODO(b/285250939): Default this to true then remove once the Compose QS expandables have + // proven that the new implementation is robust. + useModifierBasedImplementation: Boolean = false, content: @Composable (Expandable) -> Unit, ) { val controller = controller as ExpandableControllerImpl + + if (useModifierBasedImplementation) { + Box(modifier.expandable(controller, onClick, interactionSource)) { + WrappedContent(controller.expandable, controller.contentColor, content) + } + return + } + val color = controller.color val contentColor = controller.contentColor val shape = controller.shape @@ -175,21 +197,7 @@ fun Expandable( val wrappedContent = remember(content) { movableContentOf { expandable: Expandable -> - CompositionLocalProvider(LocalContentColor provides contentColor) { - // We make sure that the content itself (wrapped by the background) is at least - // 40.dp, which is the same as the M3 buttons. This applies even if onClick is - // null, to make it easier to write expandables that are sometimes clickable and - // sometimes not. There shouldn't be any Expandable smaller than 40dp because if - // the expandable is not clickable directly, then something in its content - // should be (and with a size >= 40dp). - val minSize = 40.dp - Box( - Modifier.defaultMinSize(minWidth = minSize, minHeight = minSize), - contentAlignment = Alignment.Center, - ) { - content(expandable) - } - } + WrappedContent(expandable, contentColor, content) } } @@ -209,11 +217,7 @@ fun Expandable( // Make sure we don't read animatorState directly here to avoid recomposition every time the // state changes (i.e. every frame of the animation). - val isAnimating by remember { - derivedStateOf { - controller.animatorState.value != null && controller.overlay.value != null - } - } + val isAnimating = controller.isAnimating // If this expandable is expanded when it's being directly clicked on, let's ensure that it has // the minimum interactive size followed by all M3 components (48.dp). @@ -237,58 +241,36 @@ fun Expandable( // animating. AnimatedContentInOverlay( color, - controller.boundsInComposeViewRoot.value.size, - controller.animatorState, - controller.overlay.value + controller.boundsInComposeViewRoot.size, + controller.overlay ?: error("AnimatedContentInOverlay shouldn't be composed with null overlay."), controller, wrappedContent, controller.composeViewRoot, - { controller.currentComposeViewInOverlay.value = it }, + { controller.currentComposeViewInOverlay = it }, controller.density, ) } - controller.isDialogShowing.value -> { + controller.isDialogShowing -> { Box( modifier .updateExpandableSize() .then(minInteractiveSizeModifier) .drawWithContent { /* Don't draw anything when the dialog is shown. */ } - .onGloballyPositioned { - controller.boundsInComposeViewRoot.value = it.boundsInRoot() - } + .onGloballyPositioned { controller.boundsInComposeViewRoot = it.boundsInRoot() } ) { wrappedContent(controller.expandable) } } else -> { - val clickModifier = - if (onClick != null) { - if (interactionSource != null) { - // If the caller provided an interaction source, then that means that they - // will draw the click indication themselves. - Modifier.clickable(interactionSource, indication = null) { - onClick(controller.expandable) - } - } else { - // If no interaction source is provided, we draw the default indication (a - // ripple) and make sure it's clipped by the expandable shape. - Modifier.clip(shape).clickable { onClick(controller.expandable) } - } - } else { - Modifier - } - Box( modifier .updateExpandableSize() .then(minInteractiveSizeModifier) - .then(clickModifier) + .then(clickModifier(controller, onClick, interactionSource)) .background(color, shape) .border(controller) - .onGloballyPositioned { - controller.boundsInComposeViewRoot.value = it.boundsInRoot() - } + .onGloballyPositioned { controller.boundsInComposeViewRoot = it.boundsInRoot() } ) { wrappedContent(controller.expandable) } @@ -296,12 +278,182 @@ fun Expandable( } } +@Composable +private fun WrappedContent( + expandable: Expandable, + contentColor: Color, + content: @Composable (Expandable) -> Unit, +) { + CompositionLocalProvider(LocalContentColor provides contentColor) { + // We make sure that the content itself (wrapped by the background) is at least 40.dp, which + // is the same as the M3 buttons. This applies even if onClick is null, to make it easier to + // write expandables that are sometimes clickable and sometimes not. There shouldn't be any + // Expandable smaller than 40dp because if the expandable is not clickable directly, then + // something in its content should be (and with a size >= 40dp). + val minSize = 40.dp + Box( + Modifier.defaultMinSize(minWidth = minSize, minHeight = minSize), + contentAlignment = Alignment.Center, + ) { + content(expandable) + } + } +} + +@Composable +@Stable +private fun Modifier.expandable( + controller: ExpandableController, + onClick: ((Expandable) -> Unit)? = null, + interactionSource: MutableInteractionSource? = null, +): Modifier { + val controller = controller as ExpandableControllerImpl + + val isAnimating = controller.isAnimating + val drawInOverlayModifier = + if (isAnimating) { + val graphicsLayer = rememberGraphicsLayer() + + FullScreenComposeViewInOverlay { view -> + Modifier.then(DrawExpandableInOverlayElement(view, controller, graphicsLayer)) + } + + Modifier.drawWithContent { graphicsLayer.record { this@drawWithContent.drawContent() } } + } else { + null + } + + return this.thenIf(onClick != null) { Modifier.minimumInteractiveComponentSize() } + .thenIf(!isAnimating) { + Modifier.border(controller) + .then(clickModifier(controller, onClick, interactionSource)) + .background(controller.color, controller.shape) + } + .thenIf(drawInOverlayModifier != null) { drawInOverlayModifier!! } + .onPlaced { controller.boundsInComposeViewRoot = it.boundsInRoot() } + .thenIf(!isAnimating && controller.isDialogShowing) { + Modifier.layout { measurable, constraints -> + measurable.measure(constraints).run { + layout(width, height) { /* Do not place/draw. */ } + } + } + } +} + +private data class DrawExpandableInOverlayElement( + private val overlayComposeView: ComposeView, + private val controller: ExpandableControllerImpl, + private val contentGraphicsLayer: GraphicsLayer, +) : ModifierNodeElement<DrawExpandableInOverlayNode>() { + override fun create(): DrawExpandableInOverlayNode { + return DrawExpandableInOverlayNode(overlayComposeView, controller, contentGraphicsLayer) + } + + override fun update(node: DrawExpandableInOverlayNode) { + node.update(overlayComposeView, controller, contentGraphicsLayer) + } +} + +private class DrawExpandableInOverlayNode( + composeView: ComposeView, + controller: ExpandableControllerImpl, + private var contentGraphicsLayer: GraphicsLayer, +) : Modifier.Node(), DrawModifierNode { + private var controller = controller + set(value) { + resetCurrentNodeInOverlay() + field = value + setCurrentNodeInOverlay() + } + + private var composeViewLocationOnScreen = composeView.locationOnScreen + + fun update( + composeView: ComposeView, + controller: ExpandableControllerImpl, + contentGraphicsLayer: GraphicsLayer, + ) { + this.controller = controller + this.composeViewLocationOnScreen = composeView.locationOnScreen + this.contentGraphicsLayer = contentGraphicsLayer + } + + override fun onAttach() { + setCurrentNodeInOverlay() + } + + override fun onDetach() { + resetCurrentNodeInOverlay() + } + + private fun setCurrentNodeInOverlay() { + controller.currentNodeInOverlay = this + } + + private fun resetCurrentNodeInOverlay() { + if (controller.currentNodeInOverlay == this) { + controller.currentNodeInOverlay = null + } + } + + override fun ContentDrawScope.draw() { + val state = controller.animatorState ?: return + val topOffset = state.top.toFloat() - composeViewLocationOnScreen[1] + val leftOffset = state.left.toFloat() - composeViewLocationOnScreen[0] + + translate(top = topOffset, left = leftOffset) { + // Background. + this@draw.drawBackground( + state, + controller.color, + controller.borderStroke, + size = Size(state.width.toFloat(), state.height.toFloat()), + ) + + // Content, scaled & centered w.r.t. the animated state bounds. + val contentSize = controller.boundsInComposeViewRoot.size + val contentWidth = contentSize.width + val contentHeight = contentSize.height + val scale = min(state.width / contentWidth, state.height / contentHeight) + scale(scale, pivot = Offset(state.width / 2f, state.height / 2f)) { + translate( + left = (state.width - contentWidth) / 2f, + top = (state.height - contentHeight) / 2f, + ) { + drawLayer(contentGraphicsLayer) + } + } + } + } +} + +private fun clickModifier( + controller: ExpandableControllerImpl, + onClick: ((Expandable) -> Unit)?, + interactionSource: MutableInteractionSource?, +): Modifier { + if (onClick == null) { + return Modifier + } + + if (interactionSource != null) { + // If the caller provided an interaction source, then that means that they will draw the + // click indication themselves. + return Modifier.clickable(interactionSource, indication = null) { + onClick(controller.expandable) + } + } + + // If no interaction source is provided, we draw the default indication (a ripple) and make sure + // it's clipped by the expandable shape. + return Modifier.clip(controller.shape).clickable { onClick(controller.expandable) } +} + /** Draw [content] in [overlay] while respecting its screen position given by [animatorState]. */ @Composable private fun AnimatedContentInOverlay( color: Color, sizeInOriginalLayout: Size, - animatorState: State<TransitionAnimator.State?>, overlay: ViewGroupOverlay, controller: ExpandableControllerImpl, content: @Composable (Expandable) -> Unit, @@ -324,7 +476,7 @@ private fun AnimatedContentInOverlay( // so that its content is laid out exactly the same way. .requiredSize(with(density) { sizeInOriginalLayout.toDpSize() }) .drawWithContent { - val animatorState = animatorState.value ?: return@drawWithContent + val animatorState = controller.animatorState ?: return@drawWithContent // Scale the content with the background while keeping its aspect ratio. val widthRatio = @@ -348,7 +500,8 @@ private fun AnimatedContentInOverlay( setContent { Box( Modifier.fillMaxSize().drawWithContent { - val animatorState = animatorState.value ?: return@drawWithContent + val animatorState = + controller.animatorState ?: return@drawWithContent if (!animatorState.visible) { return@drawWithContent } @@ -385,7 +538,7 @@ private fun AnimatedContentInOverlay( overlay.add(composeViewInOverlay) val startState = - animatorState.value + controller.animatorState ?: throw IllegalStateException( "AnimatedContentInOverlay shouldn't be composed with null animatorState." ) @@ -444,6 +597,7 @@ private fun ContentDrawScope.drawBackground( animatorState: TransitionAnimator.State, color: Color, border: BorderStroke?, + size: Size = this.size, ) { val topRadius = animatorState.topCornerRadius val bottomRadius = animatorState.bottomCornerRadius @@ -452,7 +606,7 @@ private fun ContentDrawScope.drawBackground( val cornerRadius = CornerRadius(topRadius) // Draw the background. - drawRoundRect(color, cornerRadius = cornerRadius) + drawRoundRect(color, cornerRadius = cornerRadius, size = size) // Draw the border. if (border != null) { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt index c5d2802c8941..a03c89626cd7 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt @@ -25,16 +25,21 @@ import androidx.compose.foundation.BorderStroke import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.MutableState +import androidx.compose.runtime.Stable import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Outline import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.node.DrawModifierNode +import androidx.compose.ui.node.invalidateDraw import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalView @@ -49,10 +54,14 @@ import com.android.systemui.animation.TransitionAnimator import kotlin.math.roundToInt /** A controller that can control animated launches from an [Expandable]. */ +@Stable interface ExpandableController { /** The [Expandable] controlled by this controller. */ val expandable: Expandable + /** Whether this controller is currently animating a launch. */ + val isAnimating: Boolean + /** Called when the [Expandable] stop being included in the composition. */ fun onDispose() } @@ -73,24 +82,9 @@ fun rememberExpandableController( val density = LocalDensity.current val layoutDirection = LocalLayoutDirection.current - // The current animation state, if we are currently animating a dialog or activity. - val animatorState = remember { mutableStateOf<TransitionAnimator.State?>(null) } - - // Whether a dialog controlled by this ExpandableController is currently showing. - val isDialogShowing = remember { mutableStateOf(false) } - - // The overlay in which we should animate the launch. - val overlay = remember { mutableStateOf<ViewGroupOverlay?>(null) } - - // The current [ComposeView] being animated in the [overlay], if any. - val currentComposeViewInOverlay = remember { mutableStateOf<View?>(null) } - - // The bounds in [composeViewRoot] of the expandable controlled by this controller. - val boundsInComposeViewRoot = remember { mutableStateOf(Rect.Zero) } - // Whether this composable is still composed. We only do the dialog exit animation if this is // true. - val isComposed = remember { mutableStateOf(true) } + var isComposed by remember { mutableStateOf(true) } val controller = remember( @@ -109,19 +103,14 @@ fun rememberExpandableController( borderStroke, composeViewRoot, density, - animatorState, - isDialogShowing, - overlay, - currentComposeViewInOverlay, - boundsInComposeViewRoot, layoutDirection, - isComposed, + { isComposed }, ) } DisposableEffect(Unit) { onDispose { - isComposed.value = false + isComposed = false if (TransitionAnimator.returnAnimationsEnabled()) { controller.onDispose() } @@ -138,17 +127,35 @@ internal class ExpandableControllerImpl( internal val borderStroke: BorderStroke?, internal val composeViewRoot: View, internal val density: Density, - internal val animatorState: MutableState<TransitionAnimator.State?>, - internal val isDialogShowing: MutableState<Boolean>, - internal val overlay: MutableState<ViewGroupOverlay?>, - internal val currentComposeViewInOverlay: MutableState<View?>, - internal val boundsInComposeViewRoot: MutableState<Rect>, private val layoutDirection: LayoutDirection, - private val isComposed: State<Boolean>, + private val isComposed: () -> Boolean, ) : ExpandableController { + /** The current animation state, if we are currently animating a dialog or activity. */ + var animatorState by mutableStateOf<TransitionAnimator.State?>(null) + private set + + /** Whether a dialog controlled by this ExpandableController is currently showing. */ + var isDialogShowing by mutableStateOf(false) + private set + + /** The overlay in which we should animate the launch. */ + var overlay by mutableStateOf<ViewGroupOverlay?>(null) + private set + + /** The current [ComposeView] being animated in the [overlay], if any. */ + var currentComposeViewInOverlay by mutableStateOf<View?>(null) + + /** The bounds in [composeViewRoot] of the expandable controlled by this controller. */ + var boundsInComposeViewRoot by mutableStateOf(Rect.Zero) + /** The [ActivityTransitionAnimator.Controller] to be cleaned up [onDispose]. */ private var activityControllerForDisposal: ActivityTransitionAnimator.Controller? = null + /** + * The current [DrawModifierNode] in the overlay, drawing the expandable during a transition. + */ + internal var currentNodeInOverlay: DrawModifierNode? = null + override val expandable: Expandable = object : Expandable { override fun activityTransitionController( @@ -158,7 +165,7 @@ internal class ExpandableControllerImpl( returnCujType: Int?, isEphemeral: Boolean, ): ActivityTransitionAnimator.Controller? { - if (!isComposed.value) { + if (!isComposed()) { return null } @@ -174,7 +181,7 @@ internal class ExpandableControllerImpl( override fun dialogTransitionController( cuj: DialogCuj? ): DialogTransitionAnimator.Controller? { - if (!isComposed.value) { + if (!isComposed()) { return null } @@ -182,6 +189,8 @@ internal class ExpandableControllerImpl( } } + override val isAnimating: Boolean by derivedStateOf { animatorState != null && overlay != null } + override fun onDispose() { activityControllerForDisposal?.onDispose() activityControllerForDisposal = null @@ -204,7 +213,11 @@ internal class ExpandableControllerImpl( override val isLaunching: Boolean = true override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { - animatorState.value = null + animatorState = null + + // Force invalidate the drawing done in the overlay whenever the animation state + // changes. + currentNodeInOverlay?.invalidateDraw() } override fun onTransitionAnimationProgress( @@ -214,7 +227,7 @@ internal class ExpandableControllerImpl( ) { // We copy state given that it's always the same object that is mutated by // ActivityTransitionAnimator. - animatorState.value = + animatorState = TransitionAnimator.State( state.top, state.bottom, @@ -227,13 +240,15 @@ internal class ExpandableControllerImpl( // Force measure and layout the ComposeView in the overlay whenever the animation // state changes. - currentComposeViewInOverlay.value?.let { - measureAndLayoutComposeViewInOverlay(it, state) - } + currentComposeViewInOverlay?.let { measureAndLayoutComposeViewInOverlay(it, state) } + + // Force invalidate the drawing done in the overlay whenever the animation state + // changes. + currentNodeInOverlay?.invalidateDraw() } override fun createAnimatorState(): TransitionAnimator.State { - val boundsInRoot = boundsInComposeViewRoot.value + val boundsInRoot = boundsInComposeViewRoot val outline = shape.createOutline( Size(boundsInRoot.width, boundsInRoot.height), @@ -285,7 +300,7 @@ internal class ExpandableControllerImpl( private fun rootLocationOnScreen(): Offset { composeViewRoot.getLocationOnScreen(rootLocationOnScreen) - val boundsInRoot = boundsInComposeViewRoot.value + val boundsInRoot = boundsInComposeViewRoot val x = rootLocationOnScreen[0] + boundsInRoot.left val y = rootLocationOnScreen[1] + boundsInRoot.top return Offset(x, y) @@ -319,14 +334,14 @@ internal class ExpandableControllerImpl( override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) { delegate.onTransitionAnimationStart(isExpandingFullyAbove) - overlay.value = transitionContainer.overlay as ViewGroupOverlay + overlay = transitionContainer.overlay as ViewGroupOverlay cujType?.let { InteractionJankMonitor.getInstance().begin(composeViewRoot, it) } } override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { cujType?.let { InteractionJankMonitor.getInstance().end(it) } delegate.onTransitionAnimationEnd(isExpandingFullyAbove) - overlay.value = null + overlay = null } } } @@ -339,14 +354,14 @@ internal class ExpandableControllerImpl( override fun startDrawingInOverlayOf(viewGroup: ViewGroup) { val newOverlay = viewGroup.overlay as ViewGroupOverlay - if (newOverlay != overlay.value) { - overlay.value = newOverlay + if (newOverlay != overlay) { + overlay = newOverlay } } override fun stopDrawingInOverlay() { - if (overlay.value != null) { - overlay.value = null + if (overlay != null) { + overlay = null } } @@ -357,7 +372,7 @@ internal class ExpandableControllerImpl( delegate.onTransitionAnimationEnd(isExpandingFullyAbove) // Make sure we don't draw this expandable when the dialog is showing. - isDialogShowing.value = true + isDialogShowing = true } } } @@ -367,16 +382,17 @@ internal class ExpandableControllerImpl( return object : TransitionAnimator.Controller by delegate { override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { delegate.onTransitionAnimationEnd(isExpandingFullyAbove) - isDialogShowing.value = false + isDialogShowing = false } } } - override fun shouldAnimateExit(): Boolean = - isComposed.value && composeViewRoot.isAttachedToWindow && composeViewRoot.isShown + override fun shouldAnimateExit(): Boolean { + return isComposed() && composeViewRoot.isAttachedToWindow && composeViewRoot.isShown + } override fun onExitAnimationCancelled() { - isDialogShowing.value = false + isDialogShowing = false } override fun jankConfigurationBuilder(): InteractionJankMonitor.Configuration.Builder? { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInOverlay.kt b/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInOverlay.kt index f5c3a834a8d7..089da4b932b2 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInOverlay.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/ui/graphics/DrawInOverlay.kt @@ -42,13 +42,19 @@ import androidx.savedstate.setViewTreeSavedStateRegistryOwner @Composable fun Modifier.drawInOverlay(): Modifier { val containerState = remember { ContainerState() } + FullScreenComposeViewInOverlay { Modifier.container(containerState) } + return this.drawInContainer(containerState, enabled = { true }) +} + +@Composable +internal fun FullScreenComposeViewInOverlay(modifier: (ComposeView) -> Modifier = { Modifier }) { val context = LocalContext.current val localView = LocalView.current val compositionContext = rememberCompositionContext() val displayMetrics = context.resources.displayMetrics val displaySize = IntSize(displayMetrics.widthPixels, displayMetrics.heightPixels) - DisposableEffect(containerState, context, localView, compositionContext, displaySize) { + DisposableEffect(context, localView, compositionContext, displaySize) { val overlay = localView.rootView.overlay as ViewGroupOverlay val view = ComposeView(context).apply { @@ -59,7 +65,8 @@ fun Modifier.drawInOverlay(): Modifier { setViewTreeViewModelStoreOwner(localView.findViewTreeViewModelStoreOwner()) setViewTreeSavedStateRegistryOwner(localView.findViewTreeSavedStateRegistryOwner()) - setContent { Box(Modifier.fillMaxSize().container(containerState)) } + val view = this + setContent { Box(modifier(view).fillMaxSize()) } } overlay.add(view) @@ -74,6 +81,4 @@ fun Modifier.drawInOverlay(): Modifier { onDispose { overlay.remove(view) } } - - return this.drawInContainer(containerState, enabled = { true }) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt index 2f38dc2a825e..fad8ae7e3ba2 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt @@ -24,7 +24,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.UserAction @@ -103,8 +102,6 @@ private fun ContentScope.BouncerScene( viewModel, dialogFactory, Modifier.element(Bouncer.Elements.Content) - // TODO(b/393516240): Use the same sysuiResTag() as views instead. - .testTag(Bouncer.Elements.Content.testTag) .overscroll(verticalOverscrollEffect) .sysuiResTag(Bouncer.TestTags.Root) .fillMaxSize(), diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index 0b17a3f71bda..9b76f15b3cd6 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -42,6 +42,7 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneTransitionLayout import com.android.compose.animation.scene.Swipe +import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.observableTransitionState import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState import com.android.compose.animation.scene.transitions @@ -87,10 +88,26 @@ val sceneTransitionsV2 = transitions { spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS) fade(AllElements) } + to(CommunalScenes.Communal, key = CommunalTransitionKeys.Swipe) { + spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS) + translate(Communal.Elements.Grid, Edge.End) + timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) } + } to(CommunalScenes.Blank) { spec = tween(durationMillis = TO_GONE_DURATION.toInt(DurationUnit.MILLISECONDS)) fade(AllElements) } + to(CommunalScenes.Blank, key = CommunalTransitionKeys.Swipe) { + spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS) + translate(Communal.Elements.Grid, Edge.End) + timestampRange(endMillis = 167) { + fade(Communal.Elements.Grid) + fade(Communal.Elements.IndicationArea) + fade(Communal.Elements.LockIcon) + fade(Communal.Elements.StatusBar) + } + timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.Scrim) } + } } val sceneTransitions = transitions { @@ -165,6 +182,7 @@ fun CommunalContainer( viewModel.communalBackground.collectAsStateWithLifecycle( initialValue = CommunalBackgroundType.ANIMATED ) + val swipeToHubEnabled by viewModel.swipeToHubEnabled.collectAsStateWithLifecycle() val state: MutableSceneTransitionLayoutState = rememberMutableSceneTransitionLayoutState( initialScene = currentSceneKey, @@ -200,15 +218,27 @@ fun CommunalContainer( scene( CommunalScenes.Blank, userActions = - if (viewModel.swipeToHubEnabled()) - mapOf(Swipe.Start(fromSource = Edge.End) to CommunalScenes.Communal) - else emptyMap(), + if (swipeToHubEnabled) { + mapOf( + Swipe.Start(fromSource = Edge.End) to + UserActionResult(CommunalScenes.Communal, CommunalTransitionKeys.Swipe) + ) + } else { + emptyMap() + }, ) { // This scene shows nothing only allowing for transitions to the communal scene. Box(modifier = Modifier.fillMaxSize()) } - scene(CommunalScenes.Communal, userActions = mapOf(Swipe.End to CommunalScenes.Blank)) { + scene( + CommunalScenes.Communal, + userActions = + mapOf( + Swipe.End to + UserActionResult(CommunalScenes.Blank, CommunalTransitionKeys.Swipe) + ), + ) { CommunalScene( backgroundType = backgroundType, colors = colors, 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 aa07370aa9cf..5e61af634bbc 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 @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.composable import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.testTag import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult @@ -56,11 +55,7 @@ constructor( @Composable override fun ContentScope.Content(modifier: Modifier) { - LockscreenScene( - lockscreenContent = lockscreenContent, - // TODO(b/393516240): Use the same sysuiResTag() as views instead. - modifier = modifier.testTag(key.rootElementKey.testTag), - ) + LockscreenScene(lockscreenContent = lockscreenContent, modifier = modifier) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt index f0d3f3e3f0a5..9c85c96c4666 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt @@ -80,6 +80,7 @@ import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.ui.compose.Icon import com.android.systemui.compose.modifiers.sysuiResTag +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsButtonViewModel import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsForegroundServicesButtonViewModel import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsSecurityButtonViewModel @@ -218,11 +219,24 @@ fun FooterActions( Spacer(Modifier.weight(1f)) } - security?.let { SecurityButton(it, Modifier.weight(1f)) } - foregroundServices?.let { ForegroundServicesButton(it) } - userSwitcher?.let { IconButton(it, Modifier.sysuiResTag("multi_user_switch")) } - IconButton(viewModel.settings, Modifier.sysuiResTag("settings_button_container")) - power?.let { IconButton(it, Modifier.sysuiResTag("pm_lite")) } + val useModifierBasedExpandable = remember { QSComposeFragment.isEnabled } + security?.let { SecurityButton(it, useModifierBasedExpandable, Modifier.weight(1f)) } + foregroundServices?.let { ForegroundServicesButton(it, useModifierBasedExpandable) } + userSwitcher?.let { + IconButton( + it, + useModifierBasedExpandable, + Modifier.sysuiResTag("multi_user_switch"), + ) + } + IconButton( + viewModel.settings, + useModifierBasedExpandable, + Modifier.sysuiResTag("settings_button_container"), + ) + power?.let { + IconButton(it, useModifierBasedExpandable, Modifier.sysuiResTag("pm_lite")) + } } } } @@ -231,6 +245,7 @@ fun FooterActions( @Composable private fun SecurityButton( model: FooterActionsSecurityButtonViewModel, + useModifierBasedExpandable: Boolean, modifier: Modifier = Modifier, ) { val onClick: ((Expandable) -> Unit)? = @@ -239,13 +254,21 @@ private fun SecurityButton( { expandable -> onClick(context, expandable) } } - TextButton(model.icon, model.text, showNewDot = false, onClick = onClick, modifier) + TextButton( + model.icon, + model.text, + showNewDot = false, + onClick = onClick, + useModifierBasedExpandable, + modifier, + ) } /** The foreground services button. */ @Composable private fun RowScope.ForegroundServicesButton( - model: FooterActionsForegroundServicesButtonViewModel + model: FooterActionsForegroundServicesButtonViewModel, + useModifierBasedExpandable: Boolean, ) { if (model.displayText) { TextButton( @@ -253,6 +276,7 @@ private fun RowScope.ForegroundServicesButton( model.text, showNewDot = model.hasNewChanges, onClick = model.onClick, + useModifierBasedExpandable, Modifier.weight(1f), ) } else { @@ -261,13 +285,18 @@ private fun RowScope.ForegroundServicesButton( contentDescription = model.text, showNewDot = model.hasNewChanges, onClick = model.onClick, + useModifierBasedExpandable, ) } } /** A button with an icon. */ @Composable -fun IconButton(model: FooterActionsButtonViewModel, modifier: Modifier = Modifier) { +fun IconButton( + model: FooterActionsButtonViewModel, + useModifierBasedExpandable: Boolean, + modifier: Modifier = Modifier, +) { Expandable( color = colorAttr(model.backgroundColor), shape = CircleShape, @@ -277,6 +306,7 @@ fun IconButton(model: FooterActionsButtonViewModel, modifier: Modifier = Modifie color = MaterialTheme.colorScheme.secondary, CornerSize(percent = 50), ), + useModifierBasedImplementation = useModifierBasedExpandable, ) { val tint = model.iconTint?.let { Color(it) } ?: Color.Unspecified Icon(model.icon, tint = tint, modifier = Modifier.size(20.dp)) @@ -290,6 +320,7 @@ private fun NumberButton( contentDescription: String, showNewDot: Boolean, onClick: (Expandable) -> Unit, + useModifierBasedExpandable: Boolean, modifier: Modifier = Modifier, ) { // By default Expandable will show a ripple above its content when clicked, and clip the content @@ -309,6 +340,7 @@ private fun NumberButton( color = MaterialTheme.colorScheme.secondary, CornerSize(percent = 50), ), + useModifierBasedImplementation = useModifierBasedExpandable, ) { Box(Modifier.size(40.dp)) { Box( @@ -355,6 +387,7 @@ private fun TextButton( text: String, showNewDot: Boolean, onClick: ((Expandable) -> Unit)?, + useModifierBasedExpandable: Boolean, modifier: Modifier = Modifier, ) { Expandable( @@ -367,12 +400,17 @@ private fun TextButton( .padding(horizontal = 4.dp) .borderOnFocus(color = MaterialTheme.colorScheme.secondary, CornerSize(50)), onClick = onClick, + useModifierBasedImplementation = useModifierBasedExpandable, ) { Row( Modifier.padding(horizontal = dimensionResource(R.dimen.qs_footer_padding)), verticalAlignment = Alignment.CenterVertically, ) { - Icon(icon, Modifier.padding(end = 12.dp).size(20.dp)) + Icon( + icon, + Modifier.padding(end = 12.dp).size(20.dp), + colorAttr(R.attr.onShadeInactiveVariant), + ) Text( text, @@ -381,6 +419,7 @@ private fun TextButton( // TODO(b/242040009): Remove this letter spacing. We should only use the M3 text // styles without modifying them. letterSpacing = 0.01.em, + color = colorAttr(R.attr.onShadeInactiveVariant), maxLines = 1, overflow = TextOverflow.Ellipsis, ) @@ -394,6 +433,7 @@ private fun TextButton( painterResource(com.android.internal.R.drawable.ic_chevron_end), contentDescription = null, Modifier.padding(start = 8.dp).size(20.dp), + colorAttr(R.attr.onShadeInactiveVariant), ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt index afdb3cbba60e..0f1cb409439f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt @@ -38,7 +38,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.boundsInWindow -import androidx.compose.ui.layout.layoutId import androidx.compose.ui.layout.onPlaced import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp @@ -51,6 +50,8 @@ import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.rememberViewModel +import com.android.systemui.media.controls.ui.composable.MediaCarousel +import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.COLLAPSED import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace import com.android.systemui.qs.composefragment.ui.GridAnchor import com.android.systemui.qs.flags.QsDetailedView @@ -66,7 +67,6 @@ import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.composable.OverlayShadeHeader import com.android.systemui.shade.ui.composable.QuickSettingsOverlayHeader -import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView @@ -106,8 +106,16 @@ constructor( } val quickSettingsContainerViewModel = rememberViewModel("QuickSettingsShadeOverlayContainer") { - quickSettingsContainerViewModelFactory.create(supportsBrightnessMirroring = true) + quickSettingsContainerViewModelFactory.create( + supportsBrightnessMirroring = true, + expansion = COLLAPSED, + ) + } + val hunPlaceholderViewModel = + rememberViewModel("QuickSettingsShadeOverlayPlaceholder") { + notificationsPlaceholderViewModelFactory.create() } + val panelCornerRadius = with(LocalDensity.current) { OverlayShade.Dimensions.PanelCornerRadius.toPx().toInt() } val showBrightnessMirror = @@ -119,13 +127,6 @@ constructor( DisposableEffect(Unit) { onDispose { contentViewModel.onPanelShapeChanged(null) } } Box(modifier = modifier.graphicsLayer { alpha = contentAlphaFromBrightnessMirror }) { - SnoozeableHeadsUpNotificationSpace( - stackScrollView = notificationStackScrollView.get(), - viewModel = - rememberViewModel("QuickSettingsShadeOverlayPlaceholder") { - notificationsPlaceholderViewModelFactory.create() - }, - ) OverlayShade( panelElement = QuickSettingsShade.Elements.Panel, alignmentOnWideScreens = Alignment.TopEnd, @@ -133,50 +134,34 @@ constructor( header = { OverlayShadeHeader( viewModel = quickSettingsContainerViewModel.shadeHeaderViewModel, - modifier = - Modifier.element(QuickSettingsShade.Elements.StatusBar) - .layoutId(SingleShadeMeasurePolicy.LayoutId.ShadeHeader), + modifier = Modifier.element(QuickSettingsShade.Elements.StatusBar), ) }, ) { - ShadeBody( + QuickSettingsContainer( viewModel = quickSettingsContainerViewModel, modifier = Modifier.onPlaced { coordinates -> - val boundsInWindow = coordinates.boundsInWindow() - val shadeScrimBounds = - ShadeScrimBounds( - left = boundsInWindow.left, - top = boundsInWindow.top, - right = boundsInWindow.right, - bottom = boundsInWindow.bottom, - ) val shape = ShadeScrimShape( - bounds = shadeScrimBounds, + bounds = ShadeScrimBounds(coordinates.boundsInWindow()), topRadius = 0, bottomRadius = panelCornerRadius, ) contentViewModel.onPanelShapeChanged(shape) }, - header = { - if (quickSettingsContainerViewModel.showHeader) { - QuickSettingsOverlayHeader( - viewModel = quickSettingsContainerViewModel.shadeHeaderViewModel, - modifier = - Modifier.element(QuickSettingsShade.Elements.Header) - .padding(top = QuickSettingsShade.Dimensions.Padding), - ) - } - }, ) } + SnoozeableHeadsUpNotificationSpace( + stackScrollView = notificationStackScrollView.get(), + viewModel = hunPlaceholderViewModel, + ) } } } -// The possible states of the `ShadeBody`. -sealed interface ShadeBodyState { +/** The possible states of the `ShadeBody`. */ +private sealed interface ShadeBodyState { data object Editing : ShadeBodyState data object TileDetails : ShadeBodyState @@ -185,10 +170,9 @@ sealed interface ShadeBodyState { } @Composable -fun ContentScope.ShadeBody( +fun ContentScope.QuickSettingsContainer( viewModel: QuickSettingsContainerViewModel, modifier: Modifier = Modifier, - header: @Composable () -> Unit, ) { val isEditing by viewModel.editModeViewModel.isEditing.collectAsStateWithLifecycle() val tileDetails = @@ -216,11 +200,10 @@ fun ContentScope.ShadeBody( TileDetails(modifier = modifier, viewModel.detailsViewModel) } - else -> { + ShadeBodyState.Default -> { QuickSettingsLayout( viewModel = viewModel, modifier = modifier.sysuiResTag("quick_settings_panel"), - header = header, ) } } @@ -232,7 +215,6 @@ fun ContentScope.ShadeBody( fun ContentScope.QuickSettingsLayout( viewModel: QuickSettingsContainerViewModel, modifier: Modifier = Modifier, - header: @Composable () -> Unit, ) { Column( verticalArrangement = Arrangement.spacedBy(QuickSettingsShade.Dimensions.Padding), @@ -244,16 +226,31 @@ fun ContentScope.QuickSettingsLayout( bottom = QuickSettingsShade.Dimensions.Padding, ), ) { - header() + if (viewModel.showHeader) { + QuickSettingsOverlayHeader( + viewModel = viewModel.shadeHeaderViewModel, + modifier = + Modifier.element(QuickSettingsShade.Elements.Header) + .padding(top = QuickSettingsShade.Dimensions.Padding), + ) + } Toolbar( modifier = Modifier.fillMaxWidth().requiredHeight(QuickSettingsShade.Dimensions.ToolbarHeight), - toolbarViewModelFactory = viewModel.toolbarViewModelFactory, + viewModel = viewModel.toolbarViewModel, ) Column( verticalArrangement = Arrangement.spacedBy(QuickSettingsShade.Dimensions.Padding), modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()), ) { + MediaCarousel( + isVisible = viewModel.showMedia, + mediaHost = viewModel.mediaHost, + carouselController = viewModel.mediaCarouselController, + usingCollapsedLandscapeMedia = true, + modifier = Modifier.padding(horizontal = QuickSettingsShade.Dimensions.Padding), + ) + BrightnessSliderContainer( viewModel = viewModel.brightnessSliderViewModel, containerColor = OverlayShade.Colors.PanelBackground, @@ -261,6 +258,7 @@ fun ContentScope.QuickSettingsLayout( Modifier.fillMaxWidth() .height(QuickSettingsShade.Dimensions.BrightnessSliderHeight), ) + Box { GridAnchor() TileGrid( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt index 8aa5bc7b7c6f..b9aca25e1675 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneTransitionLayoutDataSource.kt @@ -103,4 +103,8 @@ class SceneTransitionLayoutDataSource( override fun instantlyHideOverlay(overlay: OverlayKey) { state.snapTo(overlays = state.currentOverlays - overlay) } + + override fun freezeAndAnimateToCurrentState() { + state.currentTransition?.freezeAndAnimateToCurrentState() + } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt index 02de78bc84ce..db9035b1635b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt @@ -25,8 +25,8 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsHoveredAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer @@ -43,10 +43,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.graphicsLayer @@ -67,6 +65,7 @@ import com.android.compose.animation.scene.ValueKey import com.android.compose.animation.scene.animateElementFloatAsState import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.modifiers.thenIf +import com.android.compose.theme.colorAttr import com.android.settingslib.Utils import com.android.systemui.battery.BatteryMeterView import com.android.systemui.battery.BatteryMeterViewController @@ -77,21 +76,18 @@ import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.privacy.OngoingPrivacyChip import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.chipBackground -import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.chipHighlighted import com.android.systemui.shade.ui.composable.ShadeHeader.Colors.onScrimDim +import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.ChipPaddingHorizontal +import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.ChipPaddingVertical import com.android.systemui.shade.ui.composable.ShadeHeader.Dimensions.CollapsedHeight import com.android.systemui.shade.ui.composable.ShadeHeader.Values.ClockScale import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel.HeaderChipHighlight -import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder -import com.android.systemui.statusbar.phone.NotificationIconContainer import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.phone.StatusIconContainer import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel import com.android.systemui.statusbar.policy.Clock -import kotlinx.coroutines.launch object ShadeHeader { object Elements { @@ -110,6 +106,8 @@ object ShadeHeader { object Dimensions { val CollapsedHeight = 48.dp val ExpandedHeight = 120.dp + val ChipPaddingHorizontal = 6.dp + val ChipPaddingVertical = 4.dp } object Colors { @@ -118,12 +116,6 @@ object ShadeHeader { val ColorScheme.onScrimDim: Color get() = Color.DarkGray - - val ColorScheme.chipBackground: Color - get() = Color.DarkGray - - val ColorScheme.chipHighlighted: Color - get() = Color.LightGray } object TestTags { @@ -149,9 +141,6 @@ fun ContentScope.CollapsedShadeHeader( } } - val longerDateText by viewModel.longerDateText.collectAsStateWithLifecycle() - val shorterDateText by viewModel.shorterDateText.collectAsStateWithLifecycle() - val isShadeLayoutWide = viewModel.isShadeLayoutWide val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle() @@ -167,9 +156,9 @@ fun ContentScope.CollapsedShadeHeader( ) { Clock(scale = 1f, onClick = viewModel::onClockClicked) VariableDayDate( - longerDateText = longerDateText, - shorterDateText = shorterDateText, - chipHighlight = viewModel.notificationsChipHighlight, + longerDateText = viewModel.longerDateText, + shorterDateText = viewModel.shorterDateText, + textColor = colorAttr(android.R.attr.textColorPrimary), modifier = Modifier.element(ShadeHeader.Elements.CollapsedContentStart), ) } @@ -229,8 +218,6 @@ fun ContentScope.ExpandedShadeHeader( derivedStateOf { shouldUseExpandedFormat(layoutState.transitionState) } } - val longerDateText by viewModel.longerDateText.collectAsStateWithLifecycle() - val shorterDateText by viewModel.shorterDateText.collectAsStateWithLifecycle() val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle() Box(modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root)) { @@ -269,9 +256,9 @@ fun ContentScope.ExpandedShadeHeader( modifier = Modifier.element(ShadeHeader.Elements.ExpandedContent), ) { VariableDayDate( - longerDateText = longerDateText, - shorterDateText = shorterDateText, - chipHighlight = viewModel.notificationsChipHighlight, + longerDateText = viewModel.longerDateText, + shorterDateText = viewModel.shorterDateText, + textColor = colorAttr(android.R.attr.textColorPrimary), modifier = Modifier.widthIn(max = 90.dp), ) Spacer(modifier = Modifier.weight(1f)) @@ -316,6 +303,7 @@ fun ContentScope.OverlayShadeHeader( verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(horizontal = horizontalPadding), ) { + val chipHighlight = viewModel.notificationsChipHighlight if (isShadeLayoutWide) { Clock( scale = 1f, @@ -324,28 +312,15 @@ fun ContentScope.OverlayShadeHeader( ) Spacer(modifier = Modifier.width(5.dp)) } - val chipHighlight = viewModel.notificationsChipHighlight - NotificationIconChip( - chipHighlight = chipHighlight, + NotificationsChip( onClick = viewModel::onNotificationIconChipClicked, + backgroundColor = chipHighlight.backgroundColor(MaterialTheme.colorScheme), ) { - if (isShadeLayoutWide) { - NotificationIcons( - chipHighlight = chipHighlight, - notificationIconContainerStatusBarViewBinder = - viewModel.notificationIconContainerStatusBarViewBinder, - modifier = Modifier.width(IntrinsicSize.Min).height(20.dp), - ) - } else { - val longerDateText by viewModel.longerDateText.collectAsStateWithLifecycle() - val shorterDateText by - viewModel.shorterDateText.collectAsStateWithLifecycle() - VariableDayDate( - longerDateText = longerDateText, - shorterDateText = shorterDateText, - chipHighlight = viewModel.notificationsChipHighlight, - ) - } + VariableDayDate( + longerDateText = viewModel.longerDateText, + shorterDateText = viewModel.shorterDateText, + textColor = chipHighlight.foregroundColor(MaterialTheme.colorScheme), + ) } } }, @@ -357,14 +332,13 @@ fun ContentScope.OverlayShadeHeader( ) { val chipHighlight = viewModel.quickSettingsChipHighlight SystemIconChip( - chipHighlight = chipHighlight, + backgroundColor = chipHighlight.backgroundColor(MaterialTheme.colorScheme), onClick = viewModel::onSystemIconChipClicked, ) { StatusIcons( viewModel = viewModel, useExpandedFormat = false, modifier = Modifier.padding(end = 6.dp).weight(1f, fill = false), - chipHighlight = chipHighlight, ) BatteryIcon( createBatteryMeterViewController = @@ -534,6 +508,7 @@ private fun BatteryIcon( batteryIcon.setPercentShowMode( if (useExpandedFormat) BatteryMeterView.MODE_ESTIMATE else BatteryMeterView.MODE_ON ) + // TODO(b/397223606): Get the actual spec for this. if (chipHighlight is HeaderChipHighlight.Strong) { batteryIcon.updateColors(primaryColor, inverseColor, inverseColor) } else if (chipHighlight is HeaderChipHighlight.Weak) { @@ -546,11 +521,8 @@ private fun BatteryIcon( @Composable private fun ShadeCarrierGroup(viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier) { - Row(modifier = modifier) { - val subIds by viewModel.mobileSubIds.collectAsStateWithLifecycle() - - for (subId in subIds) { - Spacer(modifier = Modifier.width(5.dp)) + Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(5.dp)) { + for (subId in viewModel.mobileSubIds) { AndroidView( factory = { context -> ModernShadeCarrierGroupMobileView.constructAndBind( @@ -571,36 +543,10 @@ private fun ShadeCarrierGroup(viewModel: ShadeHeaderViewModel, modifier: Modifie } @Composable -private fun NotificationIcons( - chipHighlight: HeaderChipHighlight, - notificationIconContainerStatusBarViewBinder: NotificationIconContainerStatusBarViewBinder, - modifier: Modifier = Modifier, -) { - val scope = rememberCoroutineScope() - - AndroidView( - factory = { context -> - NotificationIconContainer(context, null).also { view -> - view.setOverrideIconColor(true) - scope.launch { - notificationIconContainerStatusBarViewBinder.bindWhileAttached( - view = view, - displayId = context.displayId, - ) - } - } - }, - update = { it.setUseInverseOverrideIconColor(chipHighlight is HeaderChipHighlight.Strong) }, - modifier = modifier, - ) -} - -@Composable private fun ContentScope.StatusIcons( viewModel: ShadeHeaderViewModel, useExpandedFormat: Boolean, modifier: Modifier = Modifier, - chipHighlight: HeaderChipHighlight = HeaderChipHighlight.None, ) { val localContext = LocalContext.current val themedContext = @@ -628,6 +574,8 @@ private fun ContentScope.StatusIcons( viewModel.createTintedIconManager(iconContainer, StatusBarLocation.QS) } + val chipHighlight = viewModel.quickSettingsChipHighlight + AndroidView( factory = { context -> iconManager.setTint(primaryColor, inverseColor) @@ -664,6 +612,7 @@ private fun ContentScope.StatusIcons( iconContainer.removeIgnoredSlot(locationSlot) } + // TODO(b/397223606): Get the actual spec for this. if (chipHighlight is HeaderChipHighlight.Strong) { iconManager.setTint(inverseColor, primaryColor) } else if (chipHighlight is HeaderChipHighlight.Weak) { @@ -675,62 +624,49 @@ private fun ContentScope.StatusIcons( } @Composable -private fun NotificationIconChip( - chipHighlight: HeaderChipHighlight, +private fun NotificationsChip( onClick: () -> Unit, modifier: Modifier = Modifier, - content: @Composable RowScope.() -> Unit, + backgroundColor: Color = Color.Unspecified, + content: @Composable BoxScope.() -> Unit, ) { val interactionSource = remember { MutableInteractionSource() } - Box(modifier = modifier) { - Row( - modifier = - Modifier.align(Alignment.CenterStart) - .clickable( - interactionSource = interactionSource, - indication = null, - onClick = { onClick() }, - ) - .clip(RoundedCornerShape(25.dp)) - .background( - if (chipHighlight is HeaderChipHighlight.Strong) - MaterialTheme.colorScheme.chipHighlighted - else MaterialTheme.colorScheme.chipBackground - ) - .padding(horizontal = 8.dp, vertical = 4.dp) - ) { - content() - } + Box( + modifier = + modifier + .clickable( + interactionSource = interactionSource, + indication = null, + onClick = onClick, + ) + .background(backgroundColor, RoundedCornerShape(25.dp)) + .padding(horizontal = ChipPaddingHorizontal, vertical = ChipPaddingVertical) + ) { + content() } } @Composable private fun SystemIconChip( modifier: Modifier = Modifier, - chipHighlight: HeaderChipHighlight = HeaderChipHighlight.None, + backgroundColor: Color = Color.Unspecified, onClick: (() -> Unit)? = null, content: @Composable RowScope.() -> Unit, ) { val interactionSource = remember { MutableInteractionSource() } val isHovered by interactionSource.collectIsHoveredAsState() val hoverModifier = - Modifier.clip(RoundedCornerShape(CollapsedHeight / 4)) - .background(MaterialTheme.colorScheme.onScrimDim) - val backgroundColor = - if (chipHighlight is HeaderChipHighlight.Strong) MaterialTheme.colorScheme.chipHighlighted - else MaterialTheme.colorScheme.chipBackground + with(MaterialTheme.colorScheme) { + Modifier.background(onScrimDim, RoundedCornerShape(CollapsedHeight / 4)) + } Row( verticalAlignment = Alignment.CenterVertically, modifier = modifier - .thenIf(chipHighlight !is HeaderChipHighlight.None) { - Modifier.graphicsLayer { - shape = RoundedCornerShape(25.dp) - clip = true - } - .background(backgroundColor) - .padding(horizontal = 8.dp, vertical = 4.dp) + .thenIf(backgroundColor != Color.Unspecified) { + Modifier.background(backgroundColor, RoundedCornerShape(25.dp)) + .padding(horizontal = ChipPaddingHorizontal, vertical = ChipPaddingVertical) } .thenIf(onClick != null) { Modifier.clickable( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt index 64aada52626b..8fbd0519cbdf 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/VariableDayDate.kt @@ -4,22 +4,16 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.Layout -import com.android.compose.theme.colorAttr -import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel.HeaderChipHighlight @Composable fun VariableDayDate( longerDateText: String, shorterDateText: String, - chipHighlight: HeaderChipHighlight, + textColor: Color, modifier: Modifier = Modifier, ) { - val textColor = - if (chipHighlight is HeaderChipHighlight.Strong) - colorAttr(android.R.attr.textColorPrimaryInverse) - else colorAttr(android.R.attr.textColorPrimary) - Layout( contents = listOf( diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt index 05958a212f47..907b5bc2143a 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt @@ -169,7 +169,7 @@ internal fun Modifier.element( Modifier.maybeElevateInContent(layoutImpl, content, key, currentTransitionStates) } .then(ElementModifier(layoutImpl, currentTransitionStates, content, key)) - .thenIf(layoutImpl.implicitTestTags) { Modifier.testTag(key.testTag) } + .testTag(key.testTag) } /** diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index d47210cfc428..72bb82bd41bb 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -65,8 +65,6 @@ fun SceneTransitionLayout( swipeSourceDetector: SwipeSourceDetector = DefaultEdgeDetector, swipeDetector: SwipeDetector = DefaultSwipeDetector, @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0.05f, - // TODO(b/240432457) Remove this once test utils can access the internal STLForTesting(). - implicitTestTags: Boolean = false, builder: SceneTransitionLayoutScope<ContentScope>.() -> Unit, ) { SceneTransitionLayoutForTesting( @@ -75,7 +73,6 @@ fun SceneTransitionLayout( swipeSourceDetector, swipeDetector, transitionInterceptionThreshold, - implicitTestTags = implicitTestTags, onLayoutImpl = null, builder = builder, ) @@ -728,8 +725,10 @@ class FixedDistance(private val distance: Dp) : UserActionDistance { } /** - * An internal version of [SceneTransitionLayout] to be used for tests, that provides access to the - * internal [SceneTransitionLayoutImpl] and implicitly tags all scenes and elements. + * An internal version of [SceneTransitionLayout] to be used for tests. + * + * Important: You should use this only in tests and if you need to access the underlying + * [SceneTransitionLayoutImpl]. In other cases, you should use [SceneTransitionLayout]. */ @Composable internal fun SceneTransitionLayoutForTesting( @@ -742,7 +741,6 @@ internal fun SceneTransitionLayoutForTesting( sharedElementMap: MutableMap<ElementKey, Element> = remember { mutableMapOf() }, ancestors: List<Ancestor> = remember { emptyList() }, lookaheadScope: LookaheadScope? = null, - implicitTestTags: Boolean = true, builder: SceneTransitionLayoutScope<InternalContentScope>.() -> Unit, ) { val density = LocalDensity.current @@ -767,7 +765,6 @@ internal fun SceneTransitionLayoutForTesting( directionChangeSlop = directionChangeSlop, defaultEffectFactory = defaultEffectFactory, decayAnimationSpec = decayAnimationSpec, - implicitTestTags = implicitTestTags, ) .also { onLayoutImpl?.invoke(it) } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index e3c4eb0f8bea..53996d25afdb 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -122,9 +122,6 @@ internal class SceneTransitionLayoutImpl( * This is used to enable transformations and shared elements across NestedSTLs. */ internal val ancestors: List<Ancestor> = emptyList(), - - /** Whether elements and scene should be tagged using `Modifier.testTag`. */ - internal val implicitTestTags: Boolean = false, lookaheadScope: LookaheadScope? = null, defaultEffectFactory: OverscrollFactory, ) { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt index fffc7f988acf..2d2a81542f84 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt @@ -16,6 +16,8 @@ package com.android.compose.animation.scene +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.MotionScheme import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection @@ -59,4 +61,8 @@ internal class PropertyTransformationScopeImpl(private val layoutImpl: SceneTran override val layoutDirection: LayoutDirection get() = layoutImpl.layoutDirection + + @ExperimentalMaterial3ExpressiveApi + override val motionScheme: MotionScheme + get() = layoutImpl.state.motionScheme } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt index 64cfe38d3dd5..95d6440d585e 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt @@ -171,7 +171,7 @@ internal sealed class Content( .thenIf(layoutImpl.state.isElevationPossible(content = key, element = null)) { Modifier.container(containerState) } - .thenIf(layoutImpl.implicitTestTags) { Modifier.testTag(key.testTag) } + .testTag(key.testTag) ) { CompositionLocalProvider(LocalOverscrollFactory provides lastFactory) { scope.content() @@ -290,7 +290,6 @@ internal class ContentScopeImpl( sharedElementMap = layoutImpl.elements, ancestors = ancestors, lookaheadScope = layoutImpl.lookaheadScope, - implicitTestTags = layoutImpl.implicitTestTags, ) } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt index e0b42189854a..613afe211d87 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt @@ -18,7 +18,8 @@ package com.android.compose.animation.scene.transformation import androidx.compose.animation.core.Easing import androidx.compose.animation.core.LinearEasing -import androidx.compose.ui.geometry.Offset +import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi +import androidx.compose.material3.MotionScheme import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection @@ -29,8 +30,8 @@ import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.ElementStateScope -import com.android.compose.animation.scene.Scale import com.android.compose.animation.scene.content.state.TransitionState +import com.android.compose.animation.scene.transformation.PropertyTransformation.Property import kotlinx.coroutines.CoroutineScope /** A transformation applied to one or more elements during a transition. */ @@ -126,9 +127,13 @@ interface CustomPropertyTransformation<T> : PropertyTransformation<T> { ): T } +@OptIn(ExperimentalMaterial3ExpressiveApi::class) interface PropertyTransformationScope : Density, ElementStateScope { /** The current [direction][LayoutDirection] of the layout. */ val layoutDirection: LayoutDirection + + /** The [MotionScheme] in use by the [SceneTransitionLayout]. */ + val motionScheme: MotionScheme } /** Defines the transformation-type to be applied to all elements matching [matcher]. */ diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt index 8fce7087dba6..698a80829284 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt @@ -227,7 +227,7 @@ class ElementTest { to = SceneB, transitionLayout = { state -> coroutineScope = rememberCoroutineScope() - SceneTransitionLayoutForTesting(state) { + SceneTransitionLayout(state) { scene(SceneA) { Box(Modifier.size(layoutSize)) { // Transformed element @@ -633,7 +633,7 @@ class ElementTest { val scope = rule.setContentAndCreateMainScope { - SceneTransitionLayoutForTesting(state) { + SceneTransitionLayout(state) { scene(SceneA) { Box(Modifier.element(TestElements.Foo).size(20.dp)) } scene(SceneB) {} } @@ -674,7 +674,7 @@ class ElementTest { CompositionLocalProvider( LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory() ) { - SceneTransitionLayoutForTesting(state, Modifier.size(layoutWidth, layoutHeight)) { + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { Spacer(Modifier.fillMaxSize()) } @@ -734,7 +734,7 @@ class ElementTest { CompositionLocalProvider( LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory() ) { - SceneTransitionLayoutForTesting(state, Modifier.size(layoutWidth, layoutHeight)) { + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { Spacer( Modifier.overscroll(verticalOverscrollEffect) @@ -834,7 +834,7 @@ class ElementTest { CompositionLocalProvider( LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory() ) { - SceneTransitionLayoutForTesting(state, Modifier.size(layoutWidth, layoutHeight)) { + SceneTransitionLayout(state, Modifier.size(layoutWidth, layoutHeight)) { scene(key = SceneA, userActions = mapOf(Swipe.Down to SceneB)) { Spacer(Modifier.fillMaxSize()) } @@ -893,7 +893,7 @@ class ElementTest { CompositionLocalProvider( LocalOverscrollFactory provides rememberOffsetOverscrollEffectFactory() ) { - SceneTransitionLayoutForTesting( + SceneTransitionLayout( state = state, modifier = Modifier.size(layoutWidth, layoutHeight), ) { @@ -970,7 +970,7 @@ class ElementTest { rule.setContent { touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayoutForTesting( + SceneTransitionLayout( state = state, modifier = Modifier.size(layoutWidth, layoutHeight), ) { @@ -1057,7 +1057,7 @@ class ElementTest { rule.setContent { coroutineScope = rememberCoroutineScope() - SceneTransitionLayoutForTesting(state) { + SceneTransitionLayout(state) { scene(SceneA) { Box(Modifier.size(layoutSize)) { Box( @@ -1374,7 +1374,7 @@ class ElementTest { val scope = rule.setContentAndCreateMainScope { - SceneTransitionLayoutForTesting(state, Modifier.size(layoutSize)) { + SceneTransitionLayout(state, Modifier.size(layoutSize)) { scene(SceneA) { Box(Modifier.fillMaxSize()) { Foo(Modifier.align(Alignment.TopStart)) } } @@ -1742,7 +1742,7 @@ class ElementTest { val scope = rule.setContentAndCreateMainScope { - SceneTransitionLayoutForTesting(state, Modifier.size(200.dp)) { + SceneTransitionLayout(state, Modifier.size(200.dp)) { scene(SceneA) { Foo(offset = 0.dp) } scene(SceneB) { Foo(offset = 20.dp) } scene(SceneC) { Foo(offset = 40.dp) } @@ -1828,7 +1828,7 @@ class ElementTest { val scope = rule.setContentAndCreateMainScope { - SceneTransitionLayoutForTesting(state) { + SceneTransitionLayout(state) { scene(SceneB) { Foo(Modifier.offset(40.dp, 60.dp)) } // Define A after B so that Foo is placed in A during A <=> B. @@ -1887,7 +1887,7 @@ class ElementTest { val scope = rule.setContentAndCreateMainScope { - SceneTransitionLayoutForTesting(state) { + SceneTransitionLayout(state) { scene(SceneA) { Foo() } scene(SceneB) { Foo(Modifier.offset(40.dp, 60.dp)) } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt index 98ecb644878b..04c762f43907 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/OverlayTest.kt @@ -90,7 +90,7 @@ class OverlayTest { lateinit var coroutineScope: CoroutineScope rule.setContent { coroutineScope = rememberCoroutineScope() - SceneTransitionLayoutForTesting(state, Modifier.size(200.dp)) { + SceneTransitionLayout(state, Modifier.size(200.dp)) { scene(SceneA) { Box(Modifier.fillMaxSize()) { Foo() } } overlay(OverlayA) { Foo() } } @@ -132,7 +132,7 @@ class OverlayTest { lateinit var coroutineScope: CoroutineScope rule.setContent { coroutineScope = rememberCoroutineScope() - SceneTransitionLayoutForTesting(state, Modifier.size(200.dp)) { + SceneTransitionLayout(state, Modifier.size(200.dp)) { scene(SceneA) { Box(Modifier.fillMaxSize()) { Foo() } } overlay(OverlayA) { Foo() } overlay(OverlayB) { Foo() } @@ -230,7 +230,7 @@ class OverlayTest { lateinit var coroutineScope: CoroutineScope rule.setContent { coroutineScope = rememberCoroutineScope() - SceneTransitionLayoutForTesting(state, Modifier.size(200.dp)) { + SceneTransitionLayout(state, Modifier.size(200.dp)) { scene(SceneA) { Box(Modifier.fillMaxSize()) { MovableBar() } } overlay(OverlayA) { MovableBar() } overlay(OverlayB) { MovableBar() } @@ -302,7 +302,7 @@ class OverlayTest { } var alignment by mutableStateOf(Alignment.Center) rule.setContent { - SceneTransitionLayoutForTesting(state, Modifier.size(200.dp)) { + SceneTransitionLayout(state, Modifier.size(200.dp)) { scene(SceneA) { Box(Modifier.fillMaxSize()) { Foo() } } overlay(OverlayA, alignment = alignment) { Foo() } } @@ -761,7 +761,7 @@ class OverlayTest { val movableElementChildTag = "movableElementChildTag" val scope = rule.setContentAndCreateMainScope { - SceneTransitionLayoutForTesting(state) { + SceneTransitionLayout(state) { scene(SceneA) { MovableElement(key, Modifier) { content { Box(Modifier.testTag(movableElementChildTag).size(100.dp)) } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt index 366b11d9fabd..2bf235846b32 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/PredictiveBackHandlerTest.kt @@ -250,7 +250,7 @@ class PredictiveBackHandlerTest { } rule.setContent { - SceneTransitionLayoutForTesting(state, Modifier.size(200.dp)) { + SceneTransitionLayout(state, Modifier.size(200.dp)) { scene(SceneA) { Box(Modifier.fillMaxSize()) } overlay(OverlayA) { Box(Modifier.fillMaxSize()) } overlay(OverlayB) { Box(Modifier.fillMaxSize()) } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt index 5cbc98fa4c9d..3578be4b36a7 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt @@ -97,7 +97,7 @@ class SceneTransitionLayoutTest { MutableSceneTransitionLayoutStateForTests(SceneA, EmptyTestTransitions) } - SceneTransitionLayoutForTesting(state = layoutState, modifier = Modifier.size(LayoutSize)) { + SceneTransitionLayout(state = layoutState, modifier = Modifier.size(LayoutSize)) { scene(SceneA, userActions = mapOf(Back to SceneB)) { Box(Modifier.fillMaxSize()) { SharedFoo(size = 50.dp, childOffset = 0.dp, Modifier.align(Alignment.TopEnd)) diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt index 11abbbec79bf..751b31481e3a 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt @@ -763,7 +763,7 @@ class SwipeToSceneTest { var touchSlop = 0f rule.setContent { touchSlop = LocalViewConfiguration.current.touchSlop - SceneTransitionLayoutForTesting(state, Modifier.size(layoutSize)) { + SceneTransitionLayout(state, Modifier.size(layoutSize)) { scene(SceneA, userActions = mapOf(Swipe.Start to SceneB, Swipe.End to SceneC)) { Box(Modifier.fillMaxSize()) } @@ -837,7 +837,7 @@ class SwipeToSceneTest { rule.setContent { touchSlop = LocalViewConfiguration.current.touchSlop CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) { - SceneTransitionLayoutForTesting(state, Modifier.size(layoutSize)) { + SceneTransitionLayout(state, Modifier.size(layoutSize)) { scene(SceneA, userActions = mapOf(Swipe.Start to SceneB, Swipe.End to SceneC)) { Box(Modifier.fillMaxSize()) } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedElementTransformationTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedElementTransformationTest.kt index 8b568928bde0..bb511bc27317 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedElementTransformationTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedElementTransformationTest.kt @@ -40,7 +40,7 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState import com.android.compose.animation.scene.MutableSceneTransitionLayoutStateForTests import com.android.compose.animation.scene.Scale import com.android.compose.animation.scene.SceneKey -import com.android.compose.animation.scene.SceneTransitionLayoutForTesting +import com.android.compose.animation.scene.SceneTransitionLayout import com.android.compose.animation.scene.SceneTransitions import com.android.compose.animation.scene.TestScenes import com.android.compose.animation.scene.testNestedTransition @@ -114,7 +114,7 @@ class NestedElementTransformationTest { @Composable (states: List<MutableSceneTransitionLayoutState>) -> Unit = { states -> - SceneTransitionLayoutForTesting(states[0]) { + SceneTransitionLayout(states[0]) { scene(TestScenes.SceneA, content = { TestElement(elementVariant0A) }) scene( TestScenes.SceneB, diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestContentScope.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestContentScope.kt index e56d1bed4c25..6d47babd716a 100644 --- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestContentScope.kt +++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestContentScope.kt @@ -30,7 +30,5 @@ fun TestContentScope( content: @Composable ContentScope.() -> Unit, ) { val state = rememberMutableSceneTransitionLayoutState(currentScene) - SceneTransitionLayout(state, modifier, implicitTestTags = true) { - scene(currentScene, content = content) - } + SceneTransitionLayout(state, modifier) { scene(currentScene, content = content) } } diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt index a362a370328a..f94a7ed77341 100644 --- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt +++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt @@ -137,7 +137,7 @@ fun ComposeContentTestRule.testTransition( }, changeState = changeState, transitionLayout = { state -> - SceneTransitionLayout(state, layoutModifier, implicitTestTags = true) { + SceneTransitionLayout(state, layoutModifier) { scene(fromScene, content = fromSceneContent) scene(toScene, content = toSceneContent) } @@ -163,7 +163,7 @@ fun ComposeContentTestRule.testShowOverlayTransition( ) }, transitionLayout = { state -> - SceneTransitionLayout(state, implicitTestTags = true) { + SceneTransitionLayout(state) { scene(fromScene) { fromSceneContent() } overlay(overlay) { overlayContent() } } @@ -191,7 +191,7 @@ fun ComposeContentTestRule.testHideOverlayTransition( ) }, transitionLayout = { state -> - SceneTransitionLayout(state, implicitTestTags = true) { + SceneTransitionLayout(state) { scene(toScene) { toSceneContent() } overlay(overlay) { overlayContent() } } @@ -223,7 +223,7 @@ fun ComposeContentTestRule.testReplaceOverlayTransition( ) }, transitionLayout = { state -> - SceneTransitionLayout(state, implicitTestTags = true) { + SceneTransitionLayout(state) { scene(currentScene) { currentSceneContent() } overlay(from, alignment = fromAlignment) { fromContent() } overlay(to, alignment = toAlignment) { toContent() } @@ -273,7 +273,7 @@ fun MotionTestRule<ComposeToolkit>.recordTransition( } } - SceneTransitionLayout(state, layoutModifier, implicitTestTags = true) { + SceneTransitionLayout(state, layoutModifier) { scene(fromScene, content = fromSceneContent) scene(toScene, content = toSceneContent) } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt index 8317aa39ef2b..54be4d81ea06 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt @@ -215,12 +215,7 @@ open class SimpleDigitalClockTextView( ) } - setInterpolatedViewBounds( - getInterpolatedTextBounds(), - widthMeasureSpec, - heightMeasureSpec, - force = true, - ) + setInterpolatedViewBounds(getInterpolatedTextBounds(), widthMeasureSpec, heightMeasureSpec) } override fun onDraw(canvas: Canvas) { @@ -388,7 +383,6 @@ open class SimpleDigitalClockTextView( interpBounds: Rect, widthMeasureSpec: Int = measuredWidthAndState, heightMeasureSpec: Int = measuredHeightAndState, - force: Boolean = false, ) { val heightMode = MeasureSpec.getMode(heightMeasureSpec) val widthMode = MeasureSpec.getMode(widthMeasureSpec) @@ -415,10 +409,7 @@ open class SimpleDigitalClockTextView( ) } - if (force || widthSpec != measuredWidthAndState || heightSpec != measuredHeightAndState) { - setMeasuredDimension(widthSpec, heightSpec) - parent?.requestLayout() - } + setMeasuredDimension(widthSpec, heightSpec) } private fun updateXTranslation(inPoint: Point, interpolatedTextBounds: Rect): Point { diff --git a/packages/SystemUI/docs/qs-tiles.md b/packages/SystemUI/docs/qs-tiles.md index ee388ec8e5c5..87d9b7c3b853 100644 --- a/packages/SystemUI/docs/qs-tiles.md +++ b/packages/SystemUI/docs/qs-tiles.md @@ -8,6 +8,14 @@ This document is a more or less comprehensive summary of the state and infrastru Settings tiles. It provides descriptions about the lifecycle of a tile, how to create new tiles and how SystemUI manages and displays tiles, among other topics. +A lot of the tile backend architecture is in the process of being replaced by a new architecture in +order to align with the +[recommended architecture](https://developer.android.com/topic/architecture#recommended-app-arch). + +While we are in the process of migrating, this document will try to provide a comprehensive +overview of the current architecture as well as the new one. The sections documenting the new +architecture are marked with the tag [NEW-ARCH]. + ## What are Quick Settings Tiles? Quick Settings (from now on, QS) is the expanded panel that contains shortcuts for the user to @@ -72,6 +80,27 @@ The interfaces in `QSTile` as well as other interfaces described in this documen implement plugins to add additional tiles or different behavior. For more information, see [plugins.md](plugins.md) + +#### [NEW-ARCH] Tile backend +Instead of `QSTileImpl` the tile backend is made of a view model called `QSTileViewModelImpl`, +which in turn is composed of 3 interfaces: + +* [`QSTileDataInteractor`](/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileDataInteractor.kt) +is responsible for providing the data for the tile. It is responsible for fetching the state of +the tile from the source of truth and providing that information to the tile. Typically the data +interactor will read system state from a repository or a controller and provide a flow of +domain-specific data model. + +* [`QSTileUserActionInteractor`](/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt) is responsible for handling the user actions on the tile. +This interactor decides what should happen when the user clicks, long clicks on the tile. + +* [`QSTileDataToStateMapper`](/packages/SystemUI/src/com/android/systemui/qs/tiles/base/mapper/QSTileMapper.kt) +is responsible for mapping the data received from the data interactor to a state that the view +model can use to update the UI. + +At the time being, the `QSTileViewModel`s are adapted to `QSTile`. This conversion is done by +`QSTileViewModelAdapter`. + #### Tile State Each tile has an associated `State` object that is used to communicate information to the @@ -94,6 +123,11 @@ Additionally. `BooleanState` has a `value` boolean field that usually would be s to `state == Tile#STATE_ACTIVE`. This is used by accessibility services along with `expandedAccessibilityClassName`. +#### [NEW-ARCH] Tile State +In the new architecture, the mapper generates +[`QSTileState`](packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt), +which again is converted to the old state by `QSTileViewModelAdapter`. + #### SystemUI tiles Each tile defined in SystemUI extends `QSTileImpl`. This abstract class implements some common @@ -103,6 +137,9 @@ to handle different events (refresh, click, etc.). For more information on how to implement a tile in SystemUI, see [Implementing a SystemUI tile](#implementing-a-systemui-tile). +As mentioned before, when the [NEW-ARCH] migration is complete, we will remove the `QSTileImpl` +and `QSTileViewModelAdapter` and directly use`QSTileViewModelImpl`. + ### Tile views Each Tile has a couple of associated views for displaying it in QS and QQS. These views are updated @@ -154,37 +191,24 @@ corresponding `QSTile` with its `QSTileView`, doing the following: #### Life of a tile click This is a brief run-down of what happens when a user clicks on a tile. Internal changes on the -device (for example, changes from Settings) will trigger this process starting in step 3. Throughout -this section, we assume that we are dealing with a `QSTileImpl`. - -1. User clicks on tile. The following calls happen in sequence: - 1. `QSTileViewImpl#onClickListener`. - 2. `QSTile#click`. - 3. `QSTileImpl#handleClick`. This last call sets the new state for the device by using the - associated controller. -2. State in the device changes. This is normally outside of SystemUI's control. -3. Controller receives a callback (or `Intent`) indicating the change in the device. The following - calls happen: - 1. `QSTileImpl#refreshState`, maybe passing an object with necessary information regarding the - new state. - 2. `QSTileImpl#handleRefreshState` -4. `QSTileImpl#handleUpdateState` is called to update the state with the new information. This - information can be obtained both from the `Object` passed to `refreshState` as well as from the - controller. -5. If the state has changed (in at least one element), `QSTileImpl#handleStateChanged` is called. - This will trigger a call to all the associated `QSTile.Callback#onStateChanged`, passing the - new `State`. -6. `QSTileView#onStateChanged` is called and this calls `QSTileView#handleStateChanged`. This method - maps the state into the view: - * The tile colors change to match the new state. - * `QSIconView.setIcon` is called to apply the correct state to the icon and the correct icon to - the view. - * The tile labels change to match the new state. +device (for example, changes from Settings) will trigger this process starting in step 5. + +Step | Legacy Tiles | [NEW-ARCH] Tiles +-------|-------|--------- +1 | User clicks on tile. | Same as legacy tiles. +2 | `QSTileViewImpl#onClickListener` | Same as legacy tiles. +3 | `QSTile#click` | Same as legacy tiles. +4| `QSTileImpl#handleClick` | `QSTileUserActionInteractor#handleInput` +5| State in the device changes. This is normally outside of SystemUI's control. Controller receives a callback (or `Intent`) indicating the change in the device. | Same as legacy tiles. +6 | `QSTile#refreshState`and `QSTileImpl#handleRefreshState` | `QSTileDataInteractor#tileData()` +7| `QSTileImpl#handleUpdateState` is called to update the state with the new information. This information can be obtained both from the `Object` passed to `refreshState` as well as from the controller. | The data that was generated by the data interactor is read by the `QSTileViewModelImpl.state` flow which calls `QSTileMapper#map` on the data to generate a new `QSTileState`. +8| If the state has changed (in at least one element `QSTileImpl#handleStateChanged` is called. This will trigger a call to all the associated `QSTile.Callback#onStateChanged`, passing the new `State`. | The newly mapped QSTileState is read by the `QSTileViewModelAdapter` which then maps it to a legacy `State`. Similarly to the legacy tiles, the new state is compared to the old one and if there is a difference, `QSTile.Callback#onStateChanged` is called for all the associated callbacks. +9 | `QSTileView#onStateChanged` is called and this calls `QSTileView#handleStateChanged`. This method maps the state updating tile color and label, and calling `QSIconView.setIcon` | Same as legacy tiles. ## Third party tiles (TileService) -A third party tile is any Quick Settings tile that is provided by an app (that's not SystemUI). This -is implemented by developers +A third party tile is any Quick Settings tile that is provided by an app (that's not SystemUI). +This is implemented by developers subclassing [`TileService`](/core/java/android/service/quicksettings/TileService.java) and interacting with its API. @@ -220,9 +244,9 @@ from SystemUI: * **`onTileAdded`**: called when the tile is added to QS. * **`onTileRemoved`**: called when the tile is removed from QS. * **`onStartListening`**: called when QS is opened and the tile is showing. This marks the start of - the window when calling `getQSTile` is safe and will provide the correct object. -* **`onStopListening`**: called when QS is closed or the tile is no longer visible by the user. This - marks the end of the window described in `onStartListening`. +the window when calling `getQSTile` is safe and will provide the correct object. +* **`onStopListening`**: called when QS is closed or the tile is no longer visible by the user. +This marks the end of the window described in `onStartListening`. * **`onClick`**: called when the user clicks on the tile. Additionally, the following final methods are provided: @@ -379,13 +403,14 @@ correct list of tiles. ### QSFactory +`CurrentTilesInteractorImpl` uses the `QSFactory` interface to create the tiles. + This interface provides a way of creating tiles and views from a spec. It can be used in plugins to provide different definitions for tiles. -In SystemUI there is only one implementation of this factory and that is the default -factory (`QSFactoryImpl`) in `CurrentTilesInteractorImpl`. +In SystemUI there are two implementation of this factory. The first one is `QSFactoryImpl` in used for legacy tiles. The second one is `NewQSFactory` used for [NEW-ARCH] tiles. -#### QSFactoryImpl +#### QSFactoryImpl (legacy tiles) This class implements the following method as specified in the `QSFactory` interface: @@ -402,6 +427,12 @@ This class implements the following method as specified in the `QSFactory` inter As part of filtering not valid tiles, custom tiles that don't have a corresponding valid service component are never instantiated. +#### NewQSFactory ([NEW-ARCH] tiles) + +This class also implements the `createTile` method as specified in the `QSFactory` interface. +However, it first uses the spec to get a `QSTileViewModel`. The view model is then adapted into a +`QSTile` using the `QSTileViewModelAdapter`. + ### Lifecycle of a Tile We describe first the parts of the lifecycle that are common to SystemUI tiles and third party @@ -415,7 +446,7 @@ tiles. 2. This updates the flow that `CurrentTilesInteractor` is collecting from, triggering the process described above. 3. `CurrentTilesInteractor` calls the available `QSFactory` classes in order to find one that will - be able to create a tile with that spec. Assuming that `QSFactoryImpl` managed to create the + be able to create a tile with that spec. Assuming that some factory managed to create the tile, which is some implementation of `QSTile` (either a SystemUI subclass of `QSTileImpl` or a `CustomTile`) it will be added to the current list. If the tile is available, it's stored in a map and things proceed forward. @@ -452,7 +483,7 @@ in [Third party tiles (TileService)](#third-party-tiles-tileservice). This section describes necessary and recommended steps when implementing a Quick Settings tile. Some of them are optional and depend on the requirements of the tile. -### Implementing a SystemUI tile +### Implementing a legacy SystemUI tile 1. Create a class (preferably in [`SystemUI/src/com/android/systemui/qs/tiles`](/packages/SystemUI/src/com/android/systemui/qs/tiles)) @@ -579,6 +610,70 @@ type variable of type `State`. Provides a default label for this Tile. Used by the QS Panel customizer to show a name next to each available tile. +### Implementing a [NEW-ARCH] SystemUI tile +In the new system the tiles are created in the path +[`packages/SystemUI/src/com/android/systemui/qs/tiles/impl/<spec>`](packages/SystemUI/src/com/android/systemui/qs/tiles/impl/<spec>) +where the `<spec>` should be replaced by the spec of the tile e.g. rotation for `RotationLockTile`. + +To create a new tile, the developer needs to implement the following data class and interfaces: + +[`DataModel`] is a class that describes the system state of the feature that the tile is trying to +represent. Let's refer to the type of this class as DATA_TYPE. For example a simplified version of +the data model for a flashlight tile could be a class with a boolean field that represents +whether the flashlight is on or not. + +This file should be placed in the relative path `domain/model/` down from the tile's package. + +[`QSTileDataInteractor`] There are two abstract methods that need to be implemented: +* `fun tileData(user: UserHandle, triggers: Flow<DataUpdateTrigger>): Flow<DATA_TYPE>`: This method +returns a flow of data that will be used to create the state of the tile. This is where the system +state is listened to and converted to a flow of data model. Avoid loading data or settings up +listeners on the main thread. The userHandle is the user for which the tile is created. +The triggers flow is a flow of events that can be used to trigger a refresh of the data. +The most common triggers the force update and initial request. + +* `fun availability(user: UserHandle): Flow<Boolean>`: This method returns a flow of booleans that +indicates if the tile should be shown or not. This is where the availability of the system feature +(e.g. wifi) is checked. The userHandle is the user for which the tile is created. + +This file should be placed in the relative path `domain/interactor/` down from the tile's package. + +[`QSTileUserActionInteractor`] +* `fun handleInput(input: QSTileInput)` is the method that needs to be implemented. This is the +method that will be called when the user interacts with the tile. The input parameter contains +the type of interaction (click, long click, toggle) and the DATA_TYPE of the latest data when the +input was received. + +This file should be placed in the relative path `/domain/interactor` down from the tile's package. + +[`QSTileDataToStateMapper`] +* `fun map(data: DATA_TYPE): QSTileState` is the method that needs to be implemented. This method +is responsible for mapping the data received from the data interactor to a state that the view +model can use to update the UI. This is where for example the icon should be loaded, and the +label and content description set. The map function will run on UIBackground thread, a single +thread which has higher priority than the background thread and lower than UI thread. Loading a +resource on UI thread can cause jank by blocking the UI thread. On the other end of the spectrum, +loading resources using a background dispatcher may cause jank due to background thread contention +since it is possible for the background dispatcher to use more than one background thread +at the same time. In contrast, the UIBackground dispatcher uses a single thread that is +shared by all tiles. Therefore the system will use UIBackground dispatcher to execute +the map function. + +The most important resource to load in the map function is the icon. We prefer `Icon.Loaded` with a +resource id over `Icon.Resource`, because then (a) we can guarantee that the drawable loading will +happen on the UIBackground thread and (b) we can cache the drawables using the resource id. + +This file should be placed in the relative path `/ui/mapper` down from the tile's package. + +#### Testing a [NEW-ARCH] SystemUI tile + +When writing tests, the mapper is usually a good place to start, since that is where the +business logic decisions are being made that can inform the shape of data interactor. + +We suggest taking advantage of the existing class `QSTileStateSubject`. So rather than +asserting an individual field's value, a test will assert the whole state. That can be +achieved by `QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)`. + ### Implementing a third party tile For information about this, use the Android Developer documentation diff --git a/packages/SystemUI/lint-baseline.xml b/packages/SystemUI/lint-baseline.xml index b0963d352990..993932c8a041 100644 --- a/packages/SystemUI/lint-baseline.xml +++ b/packages/SystemUI/lint-baseline.xml @@ -32784,4 +32784,15 @@ column="23"/> </issue> + <issue + id="ShadeDisplayAwareContextChecker" + message="UI elements of the shade window should use ShadeDisplayAware-annotated Context, as the shade might move between windows, and only @ShadeDisplayAware resources are updated with the new configuration correctly. Failures to do so might result in wrong dimensions for shade window classes (e.g. using the wrong density or theme). If the usage of Context is not related to display specific configuration or UI, then there is technically no need to use the annotation, and you can annotate the class with @SuppressLint("ShadeDisplayAwareContextChecker")/@Suppress("ShadeDisplayAwareContextChecker")" + errorLine1=" @QSThemedContext Context context," + errorLine2=" ~~~~~~~"> + <location + file="frameworks/base/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java" + line="126" + column="38"/> + </issue> + </issues> diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java index bd811814eb24..4140a956182c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java @@ -18,9 +18,7 @@ package com.android.keyguard; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -28,8 +26,6 @@ import static org.mockito.Mockito.when; import android.hardware.biometrics.BiometricSourceType; import android.testing.TestableLooper; -import android.text.Editable; -import android.text.TextWatcher; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -99,19 +95,6 @@ public class KeyguardMessageAreaControllerTest extends SysuiTestCase { } @Test - public void textChanged_AnnounceForAccessibility() { - ArgumentCaptor<TextWatcher> textWatcherArgumentCaptor = ArgumentCaptor.forClass( - TextWatcher.class); - mMessageAreaController.onViewAttached(); - verify(mKeyguardMessageArea).addTextChangedListener(textWatcherArgumentCaptor.capture()); - - textWatcherArgumentCaptor.getValue().afterTextChanged( - Editable.Factory.getInstance().newEditable("abc")); - verify(mKeyguardMessageArea).removeCallbacks(any(Runnable.class)); - verify(mKeyguardMessageArea).postDelayed(any(Runnable.class), anyLong()); - } - - @Test public void testSetBouncerVisible() { mMessageAreaController.setIsVisible(true); verify(mKeyguardMessageArea).setIsVisible(true); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java index e4539b75f317..0b13900d826b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java @@ -45,7 +45,6 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.media.AudioManager; -import android.os.Handler; import android.platform.test.annotations.EnableFlags; import android.provider.Settings; import android.testing.TestableLooper; @@ -75,6 +74,8 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.res.R; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.phone.SystemUIDialogManager; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.After; import org.junit.Before; @@ -107,6 +108,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { private static final String TEST_LABEL = "label"; private static final int TEST_PRESET_INDEX = 1; private static final String TEST_PRESET_NAME = "test_preset"; + private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); @Mock private SystemUIDialogManager mSystemUIDialogManager; @@ -150,11 +152,9 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { private SystemUIDialog mDialog; private SystemUIDialog.Factory mDialogFactory; private HearingDevicesDialogDelegate mDialogDelegate; - private TestableLooper mTestableLooper; @Before public void setUp() { - mTestableLooper = TestableLooper.get(this); when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter); when(mLocalBluetoothManager.getProfileManager()).thenReturn(mProfileManager); when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); @@ -186,6 +186,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { public void clickPairNewDeviceButton_intentActionMatch() { setUpDeviceDialogWithPairNewDeviceButton(); mDialog.show(); + mExecutor.runAllReady(); getPairNewDeviceButton(mDialog).performClick(); @@ -232,6 +233,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); + mExecutor.runAllReady(); assertToolsUi(0); } @@ -246,6 +248,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); + mExecutor.runAllReady(); assertToolsUi(1); } @@ -267,6 +270,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); + mExecutor.runAllReady(); assertToolsUi(2); } @@ -278,6 +282,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); + mExecutor.runAllReady(); ViewGroup presetLayout = getPresetLayout(mDialog); assertThat(presetLayout.getVisibility()).isEqualTo(View.GONE); @@ -291,7 +296,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); - mTestableLooper.processAllMessages(); + mExecutor.runAllReady(); ViewGroup presetLayout = getPresetLayout(mDialog); assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE); @@ -306,6 +311,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); + mExecutor.runAllReady(); ViewGroup ambientLayout = getAmbientLayout(mDialog); assertThat(ambientLayout.getVisibility()).isEqualTo(View.GONE); @@ -318,6 +324,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); + mExecutor.runAllReady(); ViewGroup ambientLayout = getAmbientLayout(mDialog); assertThat(ambientLayout.getVisibility()).isEqualTo(View.GONE); @@ -343,6 +350,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { public void onActiveDeviceChanged_presetExist_presetSelected() { setUpDeviceDialogWithoutPairNewDeviceButton(); mDialog.show(); + mExecutor.runAllReady(); BluetoothHapPresetInfo info = getTestPresetInfo(); when(mHapClientProfile.getAllPresetInfo(mDevice)).thenReturn(List.of(info)); when(mHapClientProfile.getActivePresetIndex(mDevice)).thenReturn(TEST_PRESET_INDEX); @@ -351,7 +359,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { assertThat(spinner.getSelectedItemPosition()).isEqualTo(-1); mDialogDelegate.onActiveDeviceChanged(mCachedDevice, BluetoothProfile.LE_AUDIO); - mTestableLooper.processAllMessages(); + mExecutor.runAllReady(); ViewGroup presetLayout = getPresetLayout(mDialog); assertThat(presetLayout.getVisibility()).isEqualTo(View.VISIBLE); @@ -381,7 +389,8 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { mActivityStarter, mDialogTransitionAnimator, mLocalBluetoothManager, - new Handler(mTestableLooper.getLooper()), + mExecutor, + mExecutor, mAudioManager, mUiEventLogger ); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt index 052d520ac92f..18b68d2fa8a3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt @@ -153,10 +153,12 @@ class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() { private class FakeViewTransitionRegistry : IViewTransitionRegistry { val registry = mutableMapOf<ViewTransitionToken, View>() + val token = ViewTransitionToken() - override fun register(token: ViewTransitionToken, view: View) { + override fun register(view: View): ViewTransitionToken { registry[token] = view view.setTag(R.id.tag_view_transition_token, token) + return token } override fun unregister(token: ViewTransitionToken) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt index ef91c793a2f3..b18eafd206ca 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/animation/ViewTransitionRegistryTest.kt @@ -25,9 +25,9 @@ import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.runner.RunWith import org.mockito.kotlin.argumentCaptor -import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever import kotlin.test.Test @SmallTest @@ -36,24 +36,22 @@ class ViewTransitionRegistryTest : SysuiTestCase() { private lateinit var view: View private lateinit var underTest: ViewTransitionRegistry - private var token: ViewTransitionToken = ViewTransitionToken() @Before fun setup() { view = FrameLayout(mContext) underTest = ViewTransitionRegistry() - token = ViewTransitionToken() } @Test fun testSuccessfulRegisterInViewTransitionRegistry() { - underTest.register(token, view) + val token = underTest.register(view) assertThat(underTest.getView(token)).isNotNull() } @Test fun testSuccessfulUnregisterInViewTransitionRegistry() { - underTest.register(token, view) + val token = underTest.register(view) assertThat(underTest.getView(token)).isNotNull() underTest.unregister(token) @@ -62,13 +60,14 @@ class ViewTransitionRegistryTest : SysuiTestCase() { @Test fun testSuccessfulUnregisterOnViewDetachedFromWindow() { - val view: View = mock { - on { getTag(R.id.tag_view_transition_token) } doReturn token - } + val view: View = mock() - underTest.register(token, view) + val token = underTest.register(view) + assertThat(token).isEqualTo(token) assertThat(underTest.getView(token)).isNotNull() + whenever(view.getTag(R.id.tag_view_transition_token)).thenReturn(token) + argumentCaptor<View.OnAttachStateChangeListener>() .apply { verify(view).addOnAttachStateChangeListener(capture()) } .firstValue @@ -76,4 +75,58 @@ class ViewTransitionRegistryTest : SysuiTestCase() { assertThat(underTest.getView(token)).isNull() } + + @Test + fun testMultipleRegisterOnSameView() { + val token = underTest.register(view) + + // multiple register on same view should return same token + assertThat(underTest.register(view)).isEqualTo(token) + + // 1st unregister doesn't remove the token from registry as refCount = 2 + underTest.unregister(token) + assertThat(underTest.getView(token)).isNotNull() + + // 2nd unregister removes the token from registry + underTest.unregister(token) + assertThat(underTest.getView(token)).isNull() + } + + @Test + fun testMultipleRegisterOnSameViewRemovedAfterViewDetached() { + val view: View = mock() + + val token = underTest.register(view) + whenever(view.getTag(R.id.tag_view_transition_token)).thenReturn(token) + + assertThat(underTest.getViewToken(view)).isEqualTo(token) + + // mock view's detach event + val caller = argumentCaptor<View.OnAttachStateChangeListener>() + .apply { verify(view).addOnAttachStateChangeListener(capture()) } + .firstValue + + // register 3 times + underTest.register(view) + underTest.register(view) + underTest.register(view) + + // unregister 1 time and verify entry should still be present in registry + underTest.unregister(token) + assertThat(underTest.getView(token)).isNotNull() + + // view's associated entry should be gone from registry, after view detaches + caller.onViewDetachedFromWindow(view) + assertThat(underTest.getView(token)).isNull() + } + + @Test + fun testDistinctViewsSameClassRegisterWithDifferentToken() { + var prev: ViewTransitionToken? = underTest.register(FrameLayout(mContext)) + for (i in 0 until 10) { + val curr = underTest.register(FrameLayout(mContext)) + assertThat(curr).isNotEqualTo(prev) + prev = curr + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index 50762edc1179..88c9e74551fd 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -21,6 +21,7 @@ import android.content.res.Configuration import android.hardware.biometrics.BiometricAuthenticator import android.hardware.biometrics.BiometricConstants import android.hardware.biometrics.BiometricManager +import android.hardware.biometrics.BiometricPrompt import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton import android.hardware.biometrics.PromptInfo import android.hardware.biometrics.PromptVerticalListContentView @@ -290,7 +291,7 @@ open class AuthContainerViewTest : SysuiTestCase() { verify(callback) .onDismissed( - eq(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED), + eq(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED), eq<ByteArray?>(null), /* credentialAttestation */ eq(authContainer?.requestId ?: 0L), ) @@ -310,7 +311,7 @@ open class AuthContainerViewTest : SysuiTestCase() { ) verify(callback) .onDismissed( - eq(AuthDialogCallback.DISMISSED_USER_CANCELED), + eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL), eq<ByteArray?>(null), /* credentialAttestation */ eq(authContainer?.requestId ?: 0L), ) @@ -325,7 +326,7 @@ open class AuthContainerViewTest : SysuiTestCase() { verify(callback) .onDismissed( - eq(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE), + eq(BiometricPrompt.DISMISSED_REASON_NEGATIVE), eq<ByteArray?>(null), /* credentialAttestation */ eq(authContainer?.requestId ?: 0L), ) @@ -352,7 +353,7 @@ open class AuthContainerViewTest : SysuiTestCase() { verify(callback) .onDismissed( - eq(AuthDialogCallback.DISMISSED_ERROR), + eq(BiometricPrompt.DISMISSED_REASON_ERROR), eq<ByteArray?>(null), /* credentialAttestation */ eq(authContainer?.requestId ?: 0L), ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java index acc97a9f8642..a1a2aa70d869 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -138,9 +138,9 @@ public class AuthControllerTest extends SysuiTestCase { @Mock private IBiometricContextListener mContextListener; @Mock - private AuthDialog mDialog1; + private AuthContainerView mDialog1; @Mock - private AuthDialog mDialog2; + private AuthContainerView mDialog2; @Mock private CommandQueue mCommandQueue; @Mock @@ -382,7 +382,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception { showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null, /* credentialAttestation */ mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( @@ -393,7 +393,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE, null, /* credentialAttestation */ mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( @@ -404,7 +404,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED, null, /* credentialAttestation */ mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( @@ -415,7 +415,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED, null, /* credentialAttestation */ mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( @@ -426,7 +426,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonError_whenDismissedByError() throws Exception { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_ERROR, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_ERROR, null, /* credentialAttestation */ mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( @@ -437,7 +437,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonServerRequested_whenDismissedByServer() throws Exception { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED, null, /* credentialAttestation */ mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( @@ -452,7 +452,7 @@ public class AuthControllerTest extends SysuiTestCase { final byte[] credentialAttestation = generateRandomHAT(); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED, credentialAttestation, mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED), @@ -462,7 +462,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testSendsReasonContentViewMoreOptions_whenButtonPressed() throws Exception { showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS, null, /* credentialAttestation */ mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( @@ -696,7 +696,7 @@ public class AuthControllerTest extends SysuiTestCase { final byte[] credentialAttestation = generateRandomHAT(); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED, credentialAttestation, mAuthController.mCurrentDialog.getRequestId()); verify(mReceiver).onDialogDismissed( eq(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED), @@ -755,7 +755,7 @@ public class AuthControllerTest extends SysuiTestCase { public void testDoesNotCrash_whenTryAgainPressedAfterDismissal() { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final long requestID = mAuthController.mCurrentDialog.getRequestId(); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null, /* credentialAttestation */requestID); mAuthController.onTryAgainPressed(requestID); } @@ -764,7 +764,7 @@ public class AuthControllerTest extends SysuiTestCase { public void testDoesNotCrash_whenDeviceCredentialPressedAfterDismissal() { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); final long requestID = mAuthController.mCurrentDialog.getRequestId(); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */, requestID); mAuthController.onDeviceCredentialPressed(requestID); } @@ -818,7 +818,7 @@ public class AuthControllerTest extends SysuiTestCase { // WHEN dialog is shown and then dismissed showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); - mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED, + mAuthController.onDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */, mAuthController.mCurrentDialog.getRequestId()); @@ -1218,14 +1218,14 @@ public class AuthControllerTest extends SysuiTestCase { } @Override - protected AuthDialog buildDialog(DelayableExecutor bgExecutor, PromptInfo promptInfo, + protected AuthContainerView buildDialog(DelayableExecutor bgExecutor, PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, String opPackageName, boolean skipIntro, long operationId, long requestId, WakefulnessLifecycle wakefulnessLifecycle, UserManager userManager, LockPatternUtils lockPatternUtils, PromptViewModel viewModel) { - AuthDialog dialog; + AuthContainerView dialog; if (mBuildCount == 0) { dialog = mDialog1; } else if (mBuildCount == 1) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java index 197cb843ba5f..9c3ef0426ee0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricNotificationDialogFactoryTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; @@ -39,6 +40,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor; import com.android.systemui.statusbar.phone.SystemUIDialog; import org.junit.Before; @@ -65,22 +67,25 @@ public class BiometricNotificationDialogFactoryTest extends SysuiTestCase { @Mock SystemUIDialog.Factory mSystemUIDialogFactory; @Mock SystemUIDialog mDialog; @Mock BiometricNotificationDialogFactory.ActivityStarter mActivityStarter; - private final ArgumentCaptor<DialogInterface.OnClickListener> mOnClickListenerArgumentCaptor = ArgumentCaptor.forClass(DialogInterface.OnClickListener.class); private final ArgumentCaptor<Intent> mIntentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); private BiometricNotificationDialogFactory mDialogFactory; + private FakeShadeDialogContextInteractor mDialogContextInteractor; @Before public void setUp() throws ExecutionException, InterruptedException { when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true); when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true); - when(mSystemUIDialogFactory.create()).thenReturn(mDialog); + when(mSystemUIDialogFactory.create(any(Context.class))).thenReturn(mDialog); + + mDialogContextInteractor = new FakeShadeDialogContextInteractor(mContext); mDialogFactory = new BiometricNotificationDialogFactory( mResources, mSystemUIDialogFactory, + mDialogContextInteractor, mFingerprintManager, mFaceManager ); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt index 1a3606e413cc..da25bcac6c95 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt @@ -35,6 +35,7 @@ import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent @@ -44,6 +45,7 @@ import org.junit.runner.RunWith import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(ParameterizedAndroidJunit4::class) class CommunalTransitionViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { @@ -65,7 +67,7 @@ class CommunalTransitionViewModelTest(flags: FlagsParameterization) : SysuiTestC private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository private val communalSceneRepository = kosmos.fakeCommunalSceneRepository - private val sceneInteractor = kosmos.sceneInteractor + private val sceneInteractor by lazy { kosmos.sceneInteractor } private val underTest: CommunalTransitionViewModel by lazy { kosmos.communalTransitionViewModel diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt index 329627af8ec2..e36d2455d316 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt @@ -61,6 +61,7 @@ import com.android.systemui.user.data.model.SelectionStatus import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.eq import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope @@ -73,6 +74,7 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mockito.never import org.mockito.Mockito.verify +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { @@ -80,21 +82,26 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { private val testScope: TestScope = kosmos.testScope private lateinit var underTest: SystemUIDeviceEntryFaceAuthInteractor + private val bouncerRepository = kosmos.fakeKeyguardBouncerRepository private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository - private val keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor private val faceAuthRepository = kosmos.fakeDeviceEntryFaceAuthRepository private val fakeUserRepository = kosmos.fakeUserRepository private val facePropertyRepository = kosmos.facePropertyRepository - private val fakeDeviceEntryFingerprintAuthInteractor = - kosmos.deviceEntryFingerprintAuthInteractor - private val powerInteractor = kosmos.powerInteractor private val fakeBiometricSettingsRepository = kosmos.fakeBiometricSettingsRepository - private val keyguardUpdateMonitor = kosmos.keyguardUpdateMonitor + private val keyguardUpdateMonitor by lazy { kosmos.keyguardUpdateMonitor } private val faceWakeUpTriggersConfig = kosmos.fakeFaceWakeUpTriggersConfig private val trustManager = kosmos.trustManager - private val deviceEntryFaceAuthStatusInteractor = kosmos.deviceEntryFaceAuthStatusInteractor + + private val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor } + private val fakeDeviceEntryFingerprintAuthInteractor by lazy { + kosmos.deviceEntryFingerprintAuthInteractor + } + private val powerInteractor by lazy { kosmos.powerInteractor } + private val deviceEntryFaceAuthStatusInteractor by lazy { + kosmos.deviceEntryFaceAuthStatusInteractor + } @Before fun setup() { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt index ff5fa3959c6d..7374f181760c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialNotificationCoordinatorTest.kt @@ -37,7 +37,6 @@ import com.android.systemui.testKosmos import com.android.systemui.touchpad.data.repository.FakeTouchpadRepository import com.google.common.truth.Truth.assertThat import kotlin.time.Duration.Companion.hours -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Before @@ -51,7 +50,6 @@ import org.mockito.Mockito.times import org.mockito.junit.MockitoJUnit import org.mockito.kotlin.any import org.mockito.kotlin.eq -import org.mockito.kotlin.firstValue import org.mockito.kotlin.never import org.mockito.kotlin.secondValue import org.mockito.kotlin.verify @@ -116,7 +114,6 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() { fun showTouchpadNotification() = runTestAndClear { touchpadRepository.setIsAnyTouchpadConnected(true) testScope.advanceTimeBy(LAUNCH_DELAY) - mockExistingNotification() verifyNotification( R.string.launch_touchpad_tutorial_notification_title, R.string.launch_touchpad_tutorial_notification_content, @@ -142,14 +139,10 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() { } @Test - fun showKeyboardNotificationThenDisconnectKeyboard() = runTestAndClear { + fun cancelKeyboardNotificationWhenKeyboardDisconnects() = runTestAndClear { keyboardRepository.setIsAnyKeyboardConnected(true) testScope.advanceTimeBy(LAUNCH_DELAY) - verifyNotification( - R.string.launch_keyboard_tutorial_notification_title, - R.string.launch_keyboard_tutorial_notification_content, - ) - mockExistingNotification() + mockNotifications(hasTutorialNotification = true) // After the keyboard is disconnected, i.e. there is nothing connected, the notification // should be cancelled @@ -158,22 +151,71 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() { } @Test - fun showKeyboardTouchpadNotificationThenDisconnectKeyboard() = runTestAndClear { + fun updateNotificationToTouchpadOnlyWhenKeyboardDisconnects() = runTestAndClear { keyboardRepository.setIsAnyKeyboardConnected(true) touchpadRepository.setIsAnyTouchpadConnected(true) testScope.advanceTimeBy(LAUNCH_DELAY) - mockExistingNotification() + mockNotifications(hasTutorialNotification = true) + keyboardRepository.setIsAnyKeyboardConnected(false) verify(notificationManager, times(2)) .notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any()) - // Connect both device and the first notification is for both - notificationCaptor.firstValue.verify( + // Connect both device and the first notification is for both. After the keyboard is + // disconnected, i.e. with only the touchpad left, the notification should be update to + // touchpad only + notificationCaptor.secondValue.verify( + R.string.launch_touchpad_tutorial_notification_title, + R.string.launch_touchpad_tutorial_notification_content, + ) + } + + @Test + fun updateNotificationToBothDevicesWhenTouchpadConnects() = runTestAndClear { + keyboardRepository.setIsAnyKeyboardConnected(true) + testScope.advanceTimeBy(LAUNCH_DELAY) + mockNotifications(hasTutorialNotification = true) + + touchpadRepository.setIsAnyTouchpadConnected(true) + + verify(notificationManager, times(2)) + .notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any()) + // Update the notification from keyboard to both devices + notificationCaptor.secondValue.verify( R.string.launch_keyboard_touchpad_tutorial_notification_title, R.string.launch_keyboard_touchpad_tutorial_notification_content, ) - // After the keyboard is disconnected, i.e. with only the touchpad left, the notification - // should be update to the one for only touchpad + } + + @Test + fun doNotShowUpdateNotificationWhenInitialNotificationIsDismissed() = runTestAndClear { + keyboardRepository.setIsAnyKeyboardConnected(true) + testScope.advanceTimeBy(LAUNCH_DELAY) + mockNotifications(hasTutorialNotification = false) + + touchpadRepository.setIsAnyTouchpadConnected(true) + + // There's only one notification being shown throughout this scenario. We don't update the + // notification because it has been dismissed when the touchpad connects + verifyNotification( + R.string.launch_keyboard_tutorial_notification_title, + R.string.launch_keyboard_tutorial_notification_content, + ) + } + + @Test + fun showTouchpadNotificationAfterDelayAndKeyboardNotificationIsDismissed() = runTestAndClear { + keyboardRepository.setIsAnyKeyboardConnected(true) + testScope.advanceTimeBy(LAUNCH_DELAY) + mockNotifications(hasTutorialNotification = false) + + touchpadRepository.setIsAnyTouchpadConnected(true) + testScope.advanceTimeBy(LAUNCH_DELAY) + + verify(notificationManager, times(2)) + .notifyAsUser(eq(TAG), eq(NOTIFICATION_ID), notificationCaptor.capture(), any()) + // The keyboard notification was shown and dismissed; the touchpad notification is scheduled + // independently notificationCaptor.secondValue.verify( R.string.launch_touchpad_tutorial_notification_title, R.string.launch_touchpad_tutorial_notification_content, @@ -189,10 +231,12 @@ class TutorialNotificationCoordinatorTest : SysuiTestCase() { } } - // Assume that there's an existing notification when the updater checks activeNotifications - private fun mockExistingNotification() { + // Mock an active notification, so when the updater checks activeNotifications, it returns one + // with the given id. Otherwise, return an empty array (i.e. no active notifications) + private fun mockNotifications(hasTutorialNotification: Boolean) { whenever(notification.id).thenReturn(NOTIFICATION_ID) - whenever(notificationManager.activeNotifications).thenReturn(arrayOf(notification)) + val notifications = if (hasTutorialNotification) arrayOf(notification) else emptyArray() + whenever(notificationManager.activeNotifications).thenReturn(notifications) } private fun verifyNotification(@StringRes titleResId: Int, @StringRes contentResId: Int) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt index 183e4d6f624b..af6c65ec6d6d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/data/source/TestShortcuts.kt @@ -538,10 +538,9 @@ object TestShortcuts { simpleShortcutCategory(System, "System apps", "Open settings"), simpleShortcutCategory(System, "System controls", "Lock screen"), simpleShortcutCategory(System, "System controls", "View notifications"), - simpleShortcutCategory(System, "System apps", "Take a note"), simpleShortcutCategory(System, "System controls", "Take screenshot"), simpleShortcutCategory(System, "System controls", "Go back"), - simpleShortcutCategory(MultiTasking, "Split screen", "Switch to full screen"), + simpleShortcutCategory(MultiTasking, "Split screen", "Use full screen"), simpleShortcutCategory( MultiTasking, "Split screen", @@ -570,7 +569,6 @@ object TestShortcuts { simpleInputGestureData( keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL ), - simpleInputGestureData(keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES), simpleInputGestureData( keyGestureType = KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT ), diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt index 6eef5eb09812..b91e259003a3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModelTest.kt @@ -337,6 +337,43 @@ class ShortcutCustomizationViewModelTest : SysuiTestCase() { } } + @Test + fun uiState_pressedKeysDescription_emptyByDefault() { + testScope.runTest { + val uiState by collectLastValue(viewModel.shortcutCustomizationUiState) + viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest) + + assertThat((uiState as AddShortcutDialog).pressedKeysDescription).isEmpty() + } + } + + @Test + fun uiState_pressedKeysDescription_updatesToNonEmptyDescriptionWhenKeyCombinationIsPressed() { + testScope.runTest { + val uiState by collectLastValue(viewModel.shortcutCustomizationUiState) + viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest) + viewModel.onShortcutKeyCombinationSelected(keyDownEventWithActionKeyPressed) + viewModel.onShortcutKeyCombinationSelected(keyUpEventWithActionKeyPressed) + + // Note that Action Key is excluded as it's already displayed on the UI + assertThat((uiState as AddShortcutDialog).pressedKeysDescription) + .isEqualTo("Ctrl, plus A") + } + } + + @Test + fun uiState_pressedKeysDescription_resetsToEmpty_onClearSelectedShortcutKeyCombination() { + testScope.runTest { + val uiState by collectLastValue(viewModel.shortcutCustomizationUiState) + viewModel.onShortcutCustomizationRequested(standardAddShortcutRequest) + viewModel.onShortcutKeyCombinationSelected(keyDownEventWithActionKeyPressed) + viewModel.onShortcutKeyCombinationSelected(keyUpEventWithActionKeyPressed) + viewModel.clearSelectedKeyCombination() + + assertThat((uiState as AddShortcutDialog).pressedKeysDescription).isEmpty() + } + } + private suspend fun openAddShortcutDialogAndSetShortcut() { openAddShortcutDialogAndPressKeyCombination() viewModel.onSetShortcut() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt index 208abf39611d..6c4325adced4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt @@ -35,12 +35,20 @@ package com.android.systemui.keyguard.domain.interactor import android.os.PowerManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository +import com.android.systemui.common.data.repository.batteryRepository +import com.android.systemui.common.data.repository.fake +import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository +import com.android.systemui.communal.domain.interactor.communalSceneInteractor +import com.android.systemui.communal.domain.interactor.setCommunalV2Available +import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository @@ -54,6 +62,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.util.KeyguardTransitionRepositorySpySubject.Companion.assertThat +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest @@ -62,6 +72,8 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor import com.android.systemui.testKosmos +import com.android.systemui.util.settings.fakeSettings +import com.google.common.truth.Truth import junit.framework.Assert.assertEquals import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.advanceTimeBy @@ -416,4 +428,25 @@ class FromAodTransitionInteractorTest : SysuiTestCase() { assertThat(transitionRepository) .startedTransition(from = KeyguardState.AOD, to = KeyguardState.LOCKSCREEN) } + + @Test + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) + fun testTransitionToGlanceableHub_onWakeUpFromAod() = + kosmos.runTest { + val user = setCommunalV2Available(true) + fakeSettings.putIntForUser(Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 1, user.id) + batteryRepository.fake.setDevicePluggedIn(true) + + val currentScene by collectLastValue(communalSceneInteractor.currentScene) + fakeCommunalSceneRepository.changeScene(CommunalScenes.Blank) + + // Communal is not showing + Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Blank) + + powerInteractor.setAwakeForTest() + testScope.advanceTimeBy(100) // account for debouncing + + Truth.assertThat(currentScene).isEqualTo(CommunalScenes.Communal) + assertThat(transitionRepository).noTransitionsStarted() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt index 29e95cd911f8..0b42898d82ae 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt @@ -23,6 +23,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.flags.EnableSceneContainer +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState @@ -46,20 +47,31 @@ import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertEquals +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThrows +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class KeyguardTransitionInteractorTest : SysuiTestCase() { - val kosmos = testKosmos() - val underTest = kosmos.keyguardTransitionInteractor - val repository = kosmos.fakeKeyguardTransitionRepository - val testScope = kosmos.testScope + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + + private lateinit var repository: FakeKeyguardTransitionRepository + private lateinit var underTest: KeyguardTransitionInteractor + + @Before + fun setup() { + repository = kosmos.fakeKeyguardTransitionRepository + underTest = kosmos.keyguardTransitionInteractor + } @Test fun transitionCollectorsReceivesOnlyAppropriateEvents() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt index 26fe379f00bf..3cff0fc96af4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt @@ -1358,6 +1358,45 @@ class LockscreenSceneTransitionInteractorTest : SysuiTestCase() { ) } + /** + * When a transition away from the lockscreen is interrupted by an `Idle(Lockscreen)`, a + * `sceneState` that was set during the transition is consumed and passed to KTF. + */ + @Test + fun transition_from_ls_scene_sceneStateSet_then_interrupted_by_idle_on_ls() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Lockscreen, + Scenes.Gone, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false), + ) + progress.value = 0.4f + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + val sceneState = KeyguardState.AOD + underTest.onSceneAboutToChange(toScene = Scenes.Lockscreen, sceneState = sceneState) + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.AOD, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + private fun assertTransition( step: TransitionStep, from: KeyguardState? = null, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt new file mode 100644 index 000000000000..052dfd52887f --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModelTest.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.kosmos.collectValues +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class DozingToDreamingTransitionViewModelTest : SysuiTestCase() { + val kosmos = testKosmos() + + val underTest by lazy { kosmos.dozingToDreamingTransitionViewModel } + + @Test + fun notificationShadeAlpha() = + kosmos.runTest { + val values by collectValues(underTest.notificationAlpha) + assertThat(values).isEmpty() + + fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.DOZING, + to = KeyguardState.DREAMING, + testScope, + ) + + assertThat(values).isNotEmpty() + values.forEach { assertThat(it).isEqualTo(0) } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt index 25c157208513..0b34a01a0fe0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt @@ -23,6 +23,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.authController import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.flags.andSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository @@ -47,6 +48,7 @@ import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableSingleShade import com.android.systemui.shade.domain.interactor.enableSplitShade +import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.testKosmos import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider @@ -123,6 +125,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa } @Test + @EnableSceneContainer fun notificationsPlacement_dualShadeSmallClock_below() = kosmos.runTest { setupState( @@ -135,6 +138,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa } @Test + @EnableSceneContainer fun notificationsPlacement_dualShadeLargeClock_topStart() = kosmos.runTest { setupState( @@ -156,6 +160,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa } @Test + @EnableSceneContainer fun areNotificationsVisible_dualShadeWideOnLockscreen_true() = kosmos.runTest { setupState( @@ -298,6 +303,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa ) { val isShadeLayoutWide by collectLastValue(kosmos.shadeRepository.isShadeLayoutWide) val collectedClockSize by collectLastValue(kosmos.keyguardClockInteractor.clockSize) + val collectedShadeMode by collectLastValue(kosmos.shadeModeInteractor.shadeMode) when (shadeMode) { ShadeMode.Dual -> kosmos.enableDualShade(wideLayout = shadeLayoutWide) ShadeMode.Single -> kosmos.enableSingleShade() @@ -309,6 +315,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa if (shadeLayoutWide != null) { assertThat(isShadeLayoutWide).isEqualTo(shadeLayoutWide) } + assertThat(collectedShadeMode).isEqualTo(shadeMode) assertThat(collectedClockSize).isEqualTo(clockSize) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt index 4e14fec8408f..943ada9346e7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/binder/SeekBarObserverTest.kt @@ -18,6 +18,9 @@ package com.android.systemui.media.controls.ui.binder import android.animation.Animator import android.animation.ObjectAnimator +import android.icu.text.MeasureFormat +import android.icu.util.Measure +import android.icu.util.MeasureUnit import android.testing.TestableLooper import android.view.View import android.widget.SeekBar @@ -30,6 +33,7 @@ import com.android.systemui.media.controls.ui.view.MediaViewHolder import com.android.systemui.media.controls.ui.viewmodel.SeekBarViewModel import com.android.systemui.res.R import com.google.common.truth.Truth.assertThat +import java.util.Locale import org.junit.Before import org.junit.Rule import org.junit.Test @@ -61,11 +65,11 @@ class SeekBarObserverTest : SysuiTestCase() { fun setUp() { context.orCreateTestableResources.addOverride( R.dimen.qs_media_enabled_seekbar_height, - enabledHeight + enabledHeight, ) context.orCreateTestableResources.addOverride( R.dimen.qs_media_disabled_seekbar_height, - disabledHeight + disabledHeight, ) seekBarView = SeekBar(context) @@ -110,14 +114,31 @@ class SeekBarObserverTest : SysuiTestCase() { @Test fun seekBarProgress() { + val elapsedTime = 3000 + val duration = (1.5 * 60 * 60 * 1000).toInt() // WHEN part of the track has been played - val data = SeekBarViewModel.Progress(true, true, true, false, 3000, 120000, true) + val data = SeekBarViewModel.Progress(true, true, true, false, elapsedTime, duration, true) observer.onChanged(data) // THEN seek bar shows the progress - assertThat(seekBarView.progress).isEqualTo(3000) - assertThat(seekBarView.max).isEqualTo(120000) - - val desc = context.getString(R.string.controls_media_seekbar_description, "00:03", "02:00") + assertThat(seekBarView.progress).isEqualTo(elapsedTime) + assertThat(seekBarView.max).isEqualTo(duration) + + val expectedProgress = + MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) + .formatMeasures(Measure(3, MeasureUnit.SECOND)) + val expectedDuration = + MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) + .formatMeasures( + Measure(1, MeasureUnit.HOUR), + Measure(30, MeasureUnit.MINUTE), + Measure(0, MeasureUnit.SECOND), + ) + val desc = + context.getString( + R.string.controls_media_seekbar_description, + expectedProgress, + expectedDuration, + ) assertThat(seekBarView.contentDescription).isEqualTo(desc) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java index a7a0c24e2163..f293614954e9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacyTest.java @@ -369,6 +369,37 @@ public class MediaOutputAdapterLegacyTest extends SysuiTestCase { } @Test + public void onBindViewHolder_initSeekbarWithUnmutedVolume_displaysMuteIcon() { + when(mMediaSwitchingController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(true); + when(mMediaDevice1.getMaxVolume()).thenReturn(TEST_MAX_VOLUME); + when(mMediaDevice1.getCurrentVolume()).thenReturn(TEST_CURRENT_VOLUME); + mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); + + assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mIconAreaLayout.getVisibility()).isEqualTo(View.VISIBLE); + + mViewHolder.mIconAreaLayout.performClick(); + verify(mMediaSwitchingController).adjustVolume(mMediaDevice1, 0); + verify(mMediaSwitchingController).logInteractionMuteDevice(mMediaDevice1); + } + + @Test + public void onBindViewHolder_initSeekbarWithMutedVolume_displaysUnmuteIcon() { + when(mMediaSwitchingController.isVolumeControlEnabled(mMediaDevice1)).thenReturn(true); + when(mMediaDevice1.getMaxVolume()).thenReturn(TEST_MAX_VOLUME); + when(mMediaDevice1.getCurrentVolume()).thenReturn(0); // muted. + mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0); + + assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewHolder.mIconAreaLayout.getVisibility()).isEqualTo(View.VISIBLE); + + mViewHolder.mIconAreaLayout.performClick(); + // Default unmute volume is 2. + verify(mMediaSwitchingController).adjustVolume(mMediaDevice1, 2); + verify(mMediaSwitchingController).logInteractionUnmuteDevice(mMediaDevice1); + } + + @Test public void onBindViewHolder_dragSeekbar_setsVolume() { mOnSeekBarChangeListenerCaptor = ArgumentCaptor.forClass( SeekBar.OnSeekBarChangeListener.class); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt index c775bfd75f6e..9e400a6c0a4c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorTest.kt @@ -19,6 +19,7 @@ package com.android.systemui.qs.panels.domain.interactor import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.collectLastValue import com.android.systemui.kosmos.runTest @@ -34,6 +35,7 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) +@EnableSceneContainer class GridLayoutTypeInteractorTest : SysuiTestCase() { val kosmos = testKosmos() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorTest.kt index 2e7aeb433e04..9fe783b98046 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/domain/interactor/QSColumnsInteractorTest.kt @@ -22,6 +22,7 @@ import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.configurationRepository import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.testCase import com.android.systemui.kosmos.testScope import com.android.systemui.qs.panels.data.repository.QSColumnsRepository @@ -76,6 +77,7 @@ class QSColumnsInteractorTest : SysuiTestCase() { } @Test + @EnableSceneContainer fun withDualShade_returnsCorrectValue() = with(kosmos) { testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt index 645efae16b8b..ab217a3f50ef 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt @@ -31,21 +31,18 @@ class MutableSelectionStateTest : SysuiTestCase() { @Test fun selectTile_isCorrectlySelected() { - assertThat(underTest.selection?.tileSpec).isNotEqualTo(TEST_SPEC) + assertThat(underTest.selection).isNotEqualTo(TEST_SPEC) - underTest.select(TEST_SPEC, manual = true) - assertThat(underTest.selection?.tileSpec).isEqualTo(TEST_SPEC) - assertThat(underTest.selection?.manual).isTrue() + underTest.select(TEST_SPEC) + assertThat(underTest.selection).isEqualTo(TEST_SPEC) underTest.unSelect() assertThat(underTest.selection).isNull() val newSpec = TileSpec.create("newSpec") - underTest.select(TEST_SPEC, manual = true) - underTest.select(newSpec, manual = false) - assertThat(underTest.selection?.tileSpec).isNotEqualTo(TEST_SPEC) - assertThat(underTest.selection?.tileSpec).isEqualTo(newSpec) - assertThat(underTest.selection?.manual).isFalse() + underTest.select(TEST_SPEC) + underTest.select(newSpec) + assertThat(underTest.selection).isEqualTo(newSpec) } companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/MediaInRowInLandscapeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/MediaInRowInLandscapeViewModelTest.kt index fdbf42c9afd8..d5e502e99de5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/MediaInRowInLandscapeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/MediaInRowInLandscapeViewModelTest.kt @@ -21,6 +21,7 @@ import android.content.res.mainResources import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QQS @@ -36,6 +37,7 @@ import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.test.Test +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before @@ -43,6 +45,7 @@ import org.junit.runner.RunWith import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters +@OptIn(ExperimentalCoroutinesApi::class) @RunWith(ParameterizedAndroidJunit4::class) @SmallTest class MediaInRowInLandscapeViewModelTest(private val testData: TestData) : SysuiTestCase() { @@ -63,6 +66,7 @@ class MediaInRowInLandscapeViewModelTest(private val testData: TestData) : Sysui } @Test + @EnableSceneContainer fun shouldMediaShowInRow() = with(kosmos) { testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelTest.kt index 241cdbfbef83..4912c319bf2e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/viewmodel/QSColumnsViewModelTest.kt @@ -21,6 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.common.ui.data.repository.configurationRepository +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.runCurrent import com.android.systemui.kosmos.testCase @@ -88,6 +89,7 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test + @EnableSceneContainer fun mediaLocationNull_dualShade_alwaysDualShadeColumns() = with(kosmos) { testScope.runTest { @@ -111,6 +113,7 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test + @EnableSceneContainer fun mediaLocationQS_dualShade_alwaysDualShadeColumns() = with(kosmos) { testScope.runTest { @@ -133,6 +136,7 @@ class QSColumnsViewModelTest : SysuiTestCase() { } @Test + @EnableSceneContainer fun mediaLocationQQS_dualShade_alwaysDualShadeColumns() = with(kosmos) { testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java index fee358a7c15d..83860ecf168b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/RotationLockTileTest.java @@ -63,6 +63,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.List; +import java.util.Optional; import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; @@ -100,7 +101,7 @@ public class RotationLockTileTest extends SysuiTestCase { @Mock private BatteryController mBatteryController; @Mock - DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController; + Optional<DeviceStateRotationLockSettingController> mDeviceStateRotationLockSettingController; @Mock RotationPolicyWrapper mRotationPolicyWrapper; @Mock diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt index 97a10e68960f..e5191e92c6d8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt @@ -23,6 +23,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.R import com.android.systemui.SysuiTestCase +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq @@ -46,24 +47,27 @@ class DataSaverDialogDelegateTest : SysuiTestCase() { private lateinit var sysuiDialogFactory: SystemUIDialog.Factory private lateinit var sysuiDialog: SystemUIDialog private lateinit var dataSaverDialogDelegate: DataSaverDialogDelegate + private lateinit var contextInteractor: FakeShadeDialogContextInteractor @Before fun setup() { sysuiDialog = mock<SystemUIDialog>() sysuiDialogFactory = mock<SystemUIDialog.Factory>() + contextInteractor = FakeShadeDialogContextInteractor(context) dataSaverDialogDelegate = DataSaverDialogDelegate( sysuiDialogFactory, - context, + contextInteractor, EmptyCoroutineContext, dataSaverController, - mock<SharedPreferences>() + mock<SharedPreferences>(), ) whenever(sysuiDialogFactory.create(eq(dataSaverDialogDelegate), eq(context))) .thenReturn(sysuiDialog) } + @Test fun delegateSetsDialogTitleCorrectly() { val expectedResId = R.string.data_saver_enable_title diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractorTest.kt index 2e9f24c67cad..87ac034a6316 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractorTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.qs.tiles.base.actions.intentInputs import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx import com.android.systemui.qs.tiles.impl.saver.domain.model.DataSaverTileModel import com.android.systemui.settings.UserFileManager +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq @@ -53,17 +54,19 @@ class DataSaverTileUserActionInteractorTest : SysuiTestCase() { private lateinit var sharedPreferences: SharedPreferences private lateinit var dialogFactory: SystemUIDialog.Factory private lateinit var underTest: DataSaverTileUserActionInteractor + private lateinit var contextInteractor: FakeShadeDialogContextInteractor @Before fun setup() { userFileManager = mock<UserFileManager>() sharedPreferences = mock<SharedPreferences>() dialogFactory = mock<SystemUIDialog.Factory>() + contextInteractor = FakeShadeDialogContextInteractor(mContext) whenever( userFileManager.getSharedPreferences( eq(DataSaverTileUserActionInteractor.PREFS), eq(Context.MODE_PRIVATE), - eq(context.userId) + eq(context.userId), ) ) .thenReturn(sharedPreferences) @@ -71,6 +74,7 @@ class DataSaverTileUserActionInteractorTest : SysuiTestCase() { underTest = DataSaverTileUserActionInteractor( context, + contextInteractor, EmptyCoroutineContext, EmptyCoroutineContext, dataSaverController, @@ -87,7 +91,7 @@ class DataSaverTileUserActionInteractorTest : SysuiTestCase() { whenever( sharedPreferences.getBoolean( eq(DataSaverTileUserActionInteractor.DIALOG_SHOWN), - any() + any(), ) ) .thenReturn(true) @@ -107,7 +111,7 @@ class DataSaverTileUserActionInteractorTest : SysuiTestCase() { whenever( sharedPreferences.getBoolean( eq(DataSaverTileUserActionInteractor.DIALOG_SHOWN), - any() + any(), ) ) .thenReturn(false) @@ -128,7 +132,7 @@ class DataSaverTileUserActionInteractorTest : SysuiTestCase() { whenever( sharedPreferences.getBoolean( eq(DataSaverTileUserActionInteractor.DIALOG_SHOWN), - any() + any(), ) ) .thenReturn(false) @@ -144,7 +148,7 @@ class DataSaverTileUserActionInteractorTest : SysuiTestCase() { whenever( sharedPreferences.getBoolean( eq(DataSaverTileUserActionInteractor.DIALOG_SHOWN), - any() + any(), ) ) .thenReturn(true) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt index 6e26fa119888..701e55d0759d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelTest.kt @@ -24,17 +24,22 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.testScope import com.android.systemui.lifecycle.activateIn +import com.android.systemui.media.controls.data.repository.mediaFilterRepository +import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.qs.composefragment.dagger.usingMediaInComposeFragment import com.android.systemui.scene.domain.startable.sceneContainerStartable import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper @@ -79,4 +84,22 @@ class QuickSettingsContainerViewModelTest : SysuiTestCase() { assertThat(underTest.showHeader).isFalse() } + + @Test + fun showMedia_activeMedia_true() = + testScope.runTest { + kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = true)) + runCurrent() + + assertThat(underTest.showMedia).isTrue() + } + + @Test + fun showMedia_noActiveMedia_false() = + testScope.runTest { + kosmos.mediaFilterRepository.addSelectedUserMediaEntry(MediaData(active = false)) + runCurrent() + + assertThat(underTest.showMedia).isFalse() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt index 80c7026b0cea..23a0f6224fb7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt @@ -757,4 +757,46 @@ class SceneInteractorTest : SysuiTestCase() { verify(processor, never()).onSceneAboutToChange(any(), any()) } + + @Test + fun changeScene_sameScene_withFreeze() = + kosmos.runTest { + val currentScene by collectLastValue(underTest.currentScene) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + val processor = mock<SceneInteractor.OnSceneAboutToChangeListener>() + underTest.registerSceneStateProcessor(processor) + verify(processor, never()).onSceneAboutToChange(any(), any()) + assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0) + + underTest.changeScene( + toScene = Scenes.Lockscreen, + loggingReason = "test", + sceneState = KeyguardState.AOD, + forceSettleToTargetScene = true, + ) + + verify(processor).onSceneAboutToChange(Scenes.Lockscreen, KeyguardState.AOD) + assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(1) + } + + @Test + fun changeScene_sameScene_withoutFreeze() = + kosmos.runTest { + val currentScene by collectLastValue(underTest.currentScene) + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + val processor = mock<SceneInteractor.OnSceneAboutToChangeListener>() + underTest.registerSceneStateProcessor(processor) + verify(processor, never()).onSceneAboutToChange(any(), any()) + assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0) + + underTest.changeScene( + toScene = Scenes.Lockscreen, + loggingReason = "test", + sceneState = KeyguardState.AOD, + forceSettleToTargetScene = false, + ) + + verify(processor, never()).onSceneAboutToChange(any(), any()) + assertThat(fakeSceneDataSource.freezeAndAnimateToCurrentStateCallCount).isEqualTo(0) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt index 35368ca8734d..9498daaf0b07 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt @@ -60,6 +60,7 @@ class ShadeDisplaysRepositoryTest : SysuiTestCase() { policies, shadeOnDefaultDisplayWhenLocked = shadeOnDefaultDisplayWhenLocked, keyguardRepository, + displayRepository, ) @Test @@ -90,6 +91,30 @@ class ShadeDisplaysRepositoryTest : SysuiTestCase() { } @Test + fun displayId_afterDisplayDisconnected_fallsBackToDefaultDisplay() = + testScope.runTest { + val underTest = createUnderTest() + globalSettings.putString( + DEVELOPMENT_SHADE_DISPLAY_AWARENESS, + FakeShadeDisplayPolicy.name, + ) + val displayId by collectLastValue(underTest.displayId) + + displayRepository.addDisplay(displayId = 1) + + FakeShadeDisplayPolicy.setDisplayId(1) + assertThat(displayId).isEqualTo(1) + + // Let's disconnect and make sure it goes back to the default one + displayRepository.removeDisplay(displayId = 1) + assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY) + + // Let's re-connect it and make sure it goes back to the non-default one + displayRepository.addDisplay(displayId = 1) + assertThat(displayId).isEqualTo(1) + } + + @Test fun policy_updatesBasedOnSettingValue_defaultDisplay() = testScope.runTest { val underTest = createUnderTest() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt index 84fc93008f49..a3dd67f85150 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorTest.kt @@ -22,6 +22,9 @@ import android.provider.AlarmClock import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.activityStarter import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback @@ -31,22 +34,32 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.argThat import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import java.util.Date +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatcher -import org.mockito.Mockito.times import org.mockito.Mockito.verify +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class ShadeHeaderClockInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() private val testScope = kosmos.testScope private val activityStarter = kosmos.activityStarter private val nextAlarmController = kosmos.nextAlarmController - val underTest = kosmos.shadeHeaderClockInteractor + private val underTest = kosmos.shadeHeaderClockInteractor @Test fun launchClockActivity_default() = @@ -55,7 +68,7 @@ class ShadeHeaderClockInteractorTest : SysuiTestCase() { verify(activityStarter) .postStartActivityDismissingKeyguard( argThat(IntentMatcherAction(AlarmClock.ACTION_SHOW_ALARMS)), - any() + any(), ) } @@ -71,6 +84,75 @@ class ShadeHeaderClockInteractorTest : SysuiTestCase() { underTest.launchClockActivity() verify(activityStarter).postStartActivityDismissingKeyguard(any()) } + + @Test + fun onTimezoneOrLocaleChanged_localeAndTimezoneChanged_emitsForEach() = + testScope.runTest { + val timeZoneOrLocaleChanges by collectValues(underTest.onTimezoneOrLocaleChanged) + + sendIntentActionBroadcast(Intent.ACTION_TIMEZONE_CHANGED) + sendIntentActionBroadcast(Intent.ACTION_LOCALE_CHANGED) + sendIntentActionBroadcast(Intent.ACTION_LOCALE_CHANGED) + sendIntentActionBroadcast(Intent.ACTION_TIMEZONE_CHANGED) + + assertThat(timeZoneOrLocaleChanges).hasSize(4) + } + + @Test + fun onTimezoneOrLocaleChanged_timeChanged_doesNotEmit() = + testScope.runTest { + val timeZoneOrLocaleChanges by collectValues(underTest.onTimezoneOrLocaleChanged) + assertThat(timeZoneOrLocaleChanges).hasSize(1) + + sendIntentActionBroadcast(Intent.ACTION_TIME_CHANGED) + sendIntentActionBroadcast(Intent.ACTION_TIME_TICK) + + // Expect only 1 event to have been emitted onStart, but no more. + assertThat(timeZoneOrLocaleChanges).hasSize(1) + } + + @Test + fun currentTime_timeChanged() = + testScope.runTest { + val currentTime by collectLastValue(underTest.currentTime) + + sendIntentActionBroadcast(Intent.ACTION_TIME_CHANGED) + val earlierTime = checkNotNull(currentTime) + + advanceTimeBy(3.seconds) + runCurrent() + + sendIntentActionBroadcast(Intent.ACTION_TIME_CHANGED) + val laterTime = checkNotNull(currentTime) + + assertThat(differenceBetween(laterTime, earlierTime)).isEqualTo(3.seconds) + } + + @Test + fun currentTime_timeTicked() = + testScope.runTest { + val currentTime by collectLastValue(underTest.currentTime) + + sendIntentActionBroadcast(Intent.ACTION_TIME_TICK) + val earlierTime = checkNotNull(currentTime) + + advanceTimeBy(7.seconds) + runCurrent() + + sendIntentActionBroadcast(Intent.ACTION_TIME_TICK) + val laterTime = checkNotNull(currentTime) + + assertThat(differenceBetween(laterTime, earlierTime)).isEqualTo(7.seconds) + } + + private fun differenceBetween(date1: Date, date2: Date): Duration { + return (date1.time - date2.time).milliseconds + } + + private fun TestScope.sendIntentActionBroadcast(intentAction: String) { + kosmos.broadcastDispatcher.sendIntentToMatchingReceiversOnly(context, Intent(intentAction)) + runCurrent() + } } private class IntentMatcherAction(private val action: String) : ArgumentMatcher<Intent> { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt index 668f568d7f46..d26e195d360a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractorImplTest.kt @@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.testScope import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.testKosmos @@ -31,6 +32,7 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) +@EnableSceneContainer class ShadeModeInteractorImplTest : SysuiTestCase() { private val kosmos = testKosmos() @@ -80,7 +82,7 @@ class ShadeModeInteractorImplTest : SysuiTestCase() { } @Test - fun isDualShade_settingEnabled_returnsTrue() = + fun isDualShade_settingEnabledSceneContainerEnabled_returnsTrue() = testScope.runTest { // TODO(b/391578667): Add a test case for user switching once the bug is fixed. val shadeMode by collectLastValue(underTest.shadeMode) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt index b8f66acf6413..dde867814159 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/startable/ShadeStartableTest.kt @@ -48,6 +48,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope @@ -59,6 +60,7 @@ import org.mockito.kotlin.verify import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(ParameterizedAndroidJunit4::class) class ShadeStartableTest(flags: FlagsParameterization) : SysuiTestCase() { @@ -103,6 +105,7 @@ class ShadeStartableTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test + @EnableSceneContainer fun hydrateShadeMode_dualShadeEnabled() = testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt index 061e04ef29f7..37b4688f753d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt @@ -25,12 +25,15 @@ import com.android.systemui.shade.domain.interactor.disableDualShade import com.android.systemui.shade.domain.interactor.enableDualShade import com.android.systemui.shade.domain.interactor.enableSingleShade import com.android.systemui.shade.domain.interactor.enableSplitShade +import com.android.systemui.shade.domain.interactor.shadeMode +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel.HeaderChipHighlight import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.fakeMobileIconsInteractor import com.android.systemui.testKosmos import com.android.systemui.util.mockito.argThat import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent @@ -43,6 +46,7 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) @EnableSceneContainer @@ -64,14 +68,15 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun mobileSubIds_update() = testScope.runTest { - val mobileSubIds by collectLastValue(underTest.mobileSubIds) mobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1) + runCurrent() - assertThat(mobileSubIds).isEqualTo(listOf(1)) + assertThat(underTest.mobileSubIds).isEqualTo(listOf(1)) mobileIconsInteractor.filteredSubscriptions.value = listOf(SUB_1, SUB_2) + runCurrent() - assertThat(mobileSubIds).isEqualTo(listOf(1, 2)) + assertThat(underTest.mobileSubIds).isEqualTo(listOf(1, 2)) } @Test @@ -116,13 +121,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun onSystemIconChipClicked_lockedOnQsShade_collapsesShadeToLockscreen() = testScope.runTest { - kosmos.enableDualShade() + setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.QuickSettingsShade) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - setDeviceEntered(false) - setScene(Scenes.Lockscreen) - setOverlay(Overlays.QuickSettingsShade) - assertThat(currentOverlays).isNotEmpty() underTest.onSystemIconChipClicked() runCurrent() @@ -134,13 +135,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun onSystemIconChipClicked_lockedOnNotifShade_expandsQsShade() = testScope.runTest { - kosmos.enableDualShade() + setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.NotificationsShade) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - setDeviceEntered(false) - setScene(Scenes.Lockscreen) - setOverlay(Overlays.NotificationsShade) - assertThat(currentOverlays).isNotEmpty() underTest.onSystemIconChipClicked() runCurrent() @@ -166,13 +163,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun onSystemIconChipClicked_unlockedOnQsShade_collapsesShadeToGone() = testScope.runTest { - kosmos.enableDualShade() + setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.QuickSettingsShade) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - setDeviceEntered(true) - setScene(Scenes.Gone) - setOverlay(Overlays.QuickSettingsShade) - assertThat(currentOverlays).isNotEmpty() underTest.onSystemIconChipClicked() runCurrent() @@ -184,13 +177,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun onSystemIconChipClicked_unlockedOnNotifShade_expandsQsShade() = testScope.runTest { - kosmos.enableDualShade() + setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.NotificationsShade) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - setDeviceEntered(true) - setScene(Scenes.Gone) - setOverlay(Overlays.NotificationsShade) - assertThat(currentOverlays).isNotEmpty() underTest.onSystemIconChipClicked() runCurrent() @@ -203,13 +192,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun onNotificationIconChipClicked_lockedOnNotifShade_collapsesShadeToLockscreen() = testScope.runTest { - kosmos.enableDualShade() + setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.NotificationsShade) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - setDeviceEntered(false) - setScene(Scenes.Lockscreen) - setOverlay(Overlays.NotificationsShade) - assertThat(currentOverlays).isNotEmpty() underTest.onNotificationIconChipClicked() runCurrent() @@ -221,13 +206,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun onNotificationIconChipClicked_lockedOnQsShade_expandsNotifShade() = testScope.runTest { - kosmos.enableDualShade() + setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.QuickSettingsShade) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - setDeviceEntered(false) - setScene(Scenes.Lockscreen) - setOverlay(Overlays.QuickSettingsShade) - assertThat(currentOverlays).isNotEmpty() underTest.onNotificationIconChipClicked() runCurrent() @@ -240,13 +221,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun onNotificationIconChipClicked_unlockedOnNotifShade_collapsesShadeToGone() = testScope.runTest { - kosmos.enableDualShade() + setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.NotificationsShade) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - setDeviceEntered(true) - setScene(Scenes.Gone) - setOverlay(Overlays.NotificationsShade) - assertThat(currentOverlays).isNotEmpty() underTest.onNotificationIconChipClicked() runCurrent() @@ -258,13 +235,9 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun onNotificationIconChipClicked_unlockedOnQsShade_expandsNotifShade() = testScope.runTest { - kosmos.enableDualShade() + setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.QuickSettingsShade) val currentScene by collectLastValue(sceneInteractor.currentScene) val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - setDeviceEntered(true) - setScene(Scenes.Gone) - setOverlay(Overlays.QuickSettingsShade) - assertThat(currentOverlays).isNotEmpty() underTest.onNotificationIconChipClicked() runCurrent() @@ -319,22 +292,13 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun highlightChips_notifsOpenInDualShade_notifsStrongQuickSettingsWeak() = testScope.runTest { - kosmos.enableDualShade() - val currentScene by collectLastValue(sceneInteractor.currentScene) - val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - // Test the lockscreen scenario. - setScene(Scenes.Lockscreen) - setOverlay(Overlays.NotificationsShade) + setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.NotificationsShade) assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.Strong) assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.Weak) // Test the unlocked scenario. - setDeviceEntered(true) - setScene(Scenes.Gone) - setOverlay(Overlays.NotificationsShade) - assertThat(currentScene).isEqualTo(Scenes.Gone) - assertThat(currentOverlays).isNotEmpty() + setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.NotificationsShade) assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.Strong) assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.Weak) } @@ -342,22 +306,13 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun highlightChips_quickSettingsOpenInDualShade_notifsWeakQuickSettingsStrong() = testScope.runTest { - kosmos.enableDualShade() - val currentScene by collectLastValue(sceneInteractor.currentScene) - val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - // Test the lockscreen scenario. - setScene(Scenes.Lockscreen) - setOverlay(Overlays.QuickSettingsShade) + setupDualShadeState(scene = Scenes.Lockscreen, overlay = Overlays.QuickSettingsShade) assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.Weak) assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.Strong) // Test the unlocked scenario. - setDeviceEntered(true) - setScene(Scenes.Gone) - setOverlay(Overlays.QuickSettingsShade) - assertThat(currentScene).isEqualTo(Scenes.Gone) - assertThat(currentOverlays).isNotEmpty() + setupDualShadeState(scene = Scenes.Gone, overlay = Overlays.QuickSettingsShade) assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.Weak) assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.Strong) } @@ -365,21 +320,13 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { @Test fun highlightChips_noOverlaysInDualShade_bothNone() = testScope.runTest { - kosmos.enableDualShade() - val currentScene by collectLastValue(sceneInteractor.currentScene) - val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) - // Test the lockscreen scenario. - setScene(Scenes.Lockscreen) - assertThat(currentOverlays).isEmpty() + setupDualShadeState(scene = Scenes.Lockscreen) assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.None) assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.None) // Test the unlocked scenario. - setDeviceEntered(true) - setScene(Scenes.Gone) - assertThat(currentScene).isEqualTo(Scenes.Gone) - assertThat(currentOverlays).isEmpty() + setupDualShadeState(scene = Scenes.Gone) assertThat(underTest.notificationsChipHighlight).isEqualTo(HeaderChipHighlight.None) assertThat(underTest.quickSettingsChipHighlight).isEqualTo(HeaderChipHighlight.None) } @@ -401,21 +348,43 @@ class ShadeHeaderViewModelTest : SysuiTestCase() { ) } - private fun setScene(key: SceneKey) { - sceneInteractor.changeScene(key, "test") + private fun TestScope.setupDualShadeState(scene: SceneKey, overlay: OverlayKey? = null) { + kosmos.enableDualShade() + val shadeMode by collectLastValue(kosmos.shadeMode) + val currentScene by collectLastValue(sceneInteractor.currentScene) + val currentOverlays by collectLastValue(sceneInteractor.currentOverlays) + if (scene == Scenes.Gone) { + // Unlock the device, marking the device has been entered. + kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( + SuccessFingerprintAuthenticationStatus(0, true) + ) + } + runCurrent() + assertThat(shadeMode).isEqualTo(ShadeMode.Dual) + + sceneInteractor.changeScene(scene, "test") + checkNotNull(currentOverlays).forEach { sceneInteractor.instantlyHideOverlay(it, "test") } + runCurrent() + overlay?.let { sceneInteractor.showOverlay(it, "test") } sceneInteractor.setTransitionState( - MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Idle(scene, setOfNotNull(overlay)) + ) ) - testScope.runCurrent() + runCurrent() + + assertThat(currentScene).isEqualTo(scene) + if (overlay == null) { + assertThat(currentOverlays).isEmpty() + } else { + assertThat(currentOverlays).containsExactly(overlay) + } } - private fun setOverlay(key: OverlayKey) { - val currentOverlays = sceneInteractor.currentOverlays.value + key - sceneInteractor.showOverlay(key, "test") + private fun setScene(key: SceneKey) { + sceneInteractor.changeScene(key, "test") sceneInteractor.setTransitionState( - MutableStateFlow<ObservableTransitionState>( - ObservableTransitionState.Idle(sceneInteractor.currentScene.value, currentOverlays) - ) + MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key)) ) testScope.runCurrent() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java index c6801f1ad9d5..3d8da6140ff7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -23,8 +23,8 @@ import static android.service.quickaccesswallet.Flags.FLAG_LAUNCH_WALLET_VIA_SYS import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -35,14 +35,12 @@ import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.PromptInfo; import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback; import android.os.Bundle; -import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.view.KeyEvent; import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; -import android.view.accessibility.Flags; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -385,30 +383,7 @@ public class CommandQueueTest extends SysuiTestCase { } @Test - @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) - public void addQsTile_withA11yQsShortcutFlagOff() { - ComponentName c = new ComponentName("testpkg", "testcls"); - - mCommandQueue.addQsTile(c); - waitForIdleSync(); - - verify(mCallbacks).addQsTile(eq(c)); - } - - @Test - @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) - public void addQsTileToFrontOrEnd_withA11yQsShortcutFlagOff_doNothing() { - ComponentName c = new ComponentName("testpkg", "testcls"); - - mCommandQueue.addQsTileToFrontOrEnd(c, true); - waitForIdleSync(); - - verifyNoMoreInteractions(mCallbacks); - } - - @Test - @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) - public void addQsTile_withA11yQsShortcutFlagOn() { + public void addQsTile() { ComponentName c = new ComponentName("testpkg", "testcls"); mCommandQueue.addQsTile(c); @@ -418,8 +393,7 @@ public class CommandQueueTest extends SysuiTestCase { } @Test - @EnableFlags(Flags.FLAG_A11Y_QS_SHORTCUT) - public void addQsTileAtTheEnd_withA11yQsShortcutFlagOn() { + public void addQsTileAtTheEnd() { ComponentName c = new ComponentName("testpkg", "testcls"); mCommandQueue.addQsTileToFrontOrEnd(c, true); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/DragDownHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/DragDownHelperTest.kt index 05d9495db091..a8aac39540fb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/DragDownHelperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/DragDownHelperTest.kt @@ -74,7 +74,7 @@ class DragDownHelperTest : SysuiTestCase() { dragDownHelper.cancelChildExpansion(expandableView, animationDuration = 0) - verify(expandableView, atLeast(1)).actualHeight = collapsedHeight + verify(expandableView, atLeast(1)).setFinalActualHeight(collapsedHeight) } @Test @@ -83,6 +83,6 @@ class DragDownHelperTest : SysuiTestCase() { dragDownHelper.cancelChildExpansion(expandableView, animationDuration = 0) - verify(expandableView, never()).actualHeight = anyInt() + verify(expandableView, never()).setFinalActualHeight(anyInt()) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt index cd66ef32180a..242da0bacea3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/PulseExpansionHandlerTest.kt @@ -86,7 +86,7 @@ class PulseExpansionHandlerTest : SysuiTestCase() { pulseExpansionHandler.reset(expandableView, animationDuration = 0) - verify(expandableView, atLeast(1)).actualHeight = collapsedHeight + verify(expandableView, atLeast(1)).setFinalActualHeight(collapsedHeight) } @Test @@ -95,6 +95,6 @@ class PulseExpansionHandlerTest : SysuiTestCase() { pulseExpansionHandler.reset(expandableView, animationDuration = 0) - verify(expandableView, never()).actualHeight = anyInt() + verify(expandableView, never()).setFinalActualHeight(anyInt()) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt index c7b3175a636f..e044d1db92a9 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModelTest.kt @@ -35,14 +35,14 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.core.StatusBarConnectedDisplays -import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.shared.CallType -import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.statusbar.phone.ongoingcall.data.repository.ongoingCallRepository import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.phone.ongoingcall.shared.model.inCallModel @@ -314,7 +314,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_inCall_nullIntent_nullClickListener() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -325,7 +325,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_inCall_positiveStartTime_validIntent_clickListenerLaunchesIntent() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -343,7 +343,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_inCall_zeroStartTime_validIntent_clickListenerLaunchesIntent() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -362,7 +362,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_inCall_nullIntent_noneClickBehavior() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -378,7 +378,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_inCall_positiveStartTime_validIntent_clickBehaviorLaunchesIntent() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -403,7 +403,7 @@ class CallChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_inCall_zeroStartTime_validIntent_clickBehaviorLaunchesIntent() = testScope.runTest { val latest by collectLastValue(underTest.chip) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt index cd3c8cdcd6e9..ccc844ad5837 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/casttootherdevice/ui/viewmodel/CastToOtherDeviceChipViewModelTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.chips.casttootherdevice.ui.viewmodel import android.content.DialogInterface -import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -48,10 +47,10 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog -import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory -import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.statusbar.policy.CastDevice import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat @@ -438,7 +437,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_projectionStateEntireScreen_clickListenerShowsScreenCastDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -454,7 +453,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_projectionStateSingleTask_clickListenerShowsScreenCastDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -475,7 +474,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_routerStateCasting_clickListenerShowsGenericCastDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -505,7 +504,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_projectionStateCasting_clickListenerHasCuj() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -525,7 +524,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_routerStateCasting_clickListenerHasCuj() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -554,7 +553,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_routerStateCasting_hasClickBehavior() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -575,7 +574,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_projectionStateCasting_hasClickBehavior() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -588,7 +587,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_projectionStateEntireScreen_clickBehaviorShowsScreenCastDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -605,7 +604,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_projectionStateSingleTask_clickBehaviorShowsScreenCastDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -627,7 +626,7 @@ class CastToOtherDeviceChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_routerStateCasting_clickBehaviorShowsGenericCastDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt index aaa9b58a45df..4993b5661373 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt @@ -38,19 +38,23 @@ import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifCh import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.core.StatusBarConnectedDisplays -import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.UnconfinedFakeHeadsUpRowRepository import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.headsup.PinnedStatus import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.When import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository -import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.testKosmos +import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat import kotlin.test.Test +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.flow.MutableStateFlow import org.junit.Before import org.junit.runner.RunWith @@ -286,15 +290,13 @@ class NotifChipsViewModelTest : SysuiTestCase() { fun chips_hasShortCriticalText_usesTextInsteadOfTime() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { this.shortCriticalText = "Arrived" - this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 30.minutes.inWholeMilliseconds) } setNotifs( listOf( @@ -340,15 +342,13 @@ class NotifChipsViewModelTest : SysuiTestCase() { fun chips_basicTime_timeHiddenIfAutomaticallyPromoted() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { this.wasPromotedAutomatically = true - this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 30.minutes.inWholeMilliseconds) } setNotifs( listOf( @@ -370,15 +370,13 @@ class NotifChipsViewModelTest : SysuiTestCase() { fun chips_basicTime_timeShownIfNotAutomaticallyPromoted() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { this.wasPromotedAutomatically = false - this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 30.minutes.inWholeMilliseconds) } setNotifs( listOf( @@ -397,18 +395,17 @@ class NotifChipsViewModelTest : SysuiTestCase() { @Test @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) - fun chips_basicTime_isShortTimeDelta() = + fun chips_basicTime_timeInFuture_isShortTimeDelta() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 3.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { - this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 13.minutes.inWholeMilliseconds) } + setNotifs( listOf( activeNotificationModel( @@ -426,17 +423,141 @@ class NotifChipsViewModelTest : SysuiTestCase() { @Test @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) + fun chips_basicTime_timeLessThanOneMinInFuture_isIconOnly() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + val currentTime = 3.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) + + val promotedContentBuilder = + PromotedNotificationContentModel.Builder("notif").apply { + this.time = When.Time(currentTime + 500) + } + + setNotifs( + listOf( + activeNotificationModel( + key = "notif", + statusBarChipIcon = createStatusBarIconViewOrNull(), + promotedContent = promotedContentBuilder.build(), + ) + ) + ) + + assertThat(latest).hasSize(1) + assertThat(latest!![0]) + .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) + } + + @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) + fun chips_basicTime_timeIsNow_isIconOnly() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + val currentTime = 62.seconds.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) + + val promotedContentBuilder = + PromotedNotificationContentModel.Builder("notif").apply { + this.time = When.Time(currentTime) + } + + setNotifs( + listOf( + activeNotificationModel( + key = "notif", + statusBarChipIcon = createStatusBarIconViewOrNull(), + promotedContent = promotedContentBuilder.build(), + ) + ) + ) + + assertThat(latest).hasSize(1) + assertThat(latest!![0]) + .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) + } + + @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) + fun chips_basicTime_timeInPast_isIconOnly() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + val currentTime = 62.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) + + val promotedContentBuilder = + PromotedNotificationContentModel.Builder("notif").apply { + this.time = When.Time(currentTime - 2.minutes.inWholeMilliseconds) + } + + setNotifs( + listOf( + activeNotificationModel( + key = "notif", + statusBarChipIcon = createStatusBarIconViewOrNull(), + promotedContent = promotedContentBuilder.build(), + ) + ) + ) + + assertThat(latest).hasSize(1) + assertThat(latest!![0]) + .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) + } + + // Not necessarily the behavior we *want* to have, but it's the currently implemented behavior. + @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) + fun chips_basicTime_timeIsInFuture_thenTimeAdvances_stillShortTimeDelta() = + kosmos.runTest { + val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) + + val promotedContentBuilder = + PromotedNotificationContentModel.Builder("notif").apply { + this.time = When.Time(currentTime + 3.minutes.inWholeMilliseconds) + } + + setNotifs( + listOf( + activeNotificationModel( + key = "notif", + statusBarChipIcon = createStatusBarIconViewOrNull(), + promotedContent = promotedContentBuilder.build(), + ) + ) + ) + + assertThat(latest).hasSize(1) + assertThat(latest!![0]) + .isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java) + + fakeSystemClock.advanceTime(5.minutes.inWholeMilliseconds) + + assertThat(latest).hasSize(1) + assertThat(latest!![0]) + .isInstanceOf(OngoingActivityChipModel.Active.ShortTimeDelta::class.java) + } + + @Test + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) fun chips_countUpTime_isTimer() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) + + val currentElapsed = + currentTime + fakeSystemClock.elapsedRealtime() - + fakeSystemClock.currentTimeMillis() + + val whenElapsed = currentElapsed - 1.minutes.inWholeMilliseconds val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.CountUp, - ) + When.Chronometer(elapsedRealtimeMillis = whenElapsed, isCountDown = false) } setNotifs( listOf( @@ -450,6 +571,8 @@ class NotifChipsViewModelTest : SysuiTestCase() { assertThat(latest).hasSize(1) assertThat(latest!![0]).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) + assertThat((latest!![0] as OngoingActivityChipModel.Active.Timer).startTimeMs) + .isEqualTo(whenElapsed) } @Test @@ -457,14 +580,19 @@ class NotifChipsViewModelTest : SysuiTestCase() { fun chips_countDownTime_isTimer() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) + + val currentElapsed = + currentTime + fakeSystemClock.elapsedRealtime() - + fakeSystemClock.currentTimeMillis() + + val whenElapsed = currentElapsed + 10.minutes.inWholeMilliseconds val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.CountDown, - ) + When.Chronometer(elapsedRealtimeMillis = whenElapsed, isCountDown = true) } setNotifs( listOf( @@ -478,6 +606,8 @@ class NotifChipsViewModelTest : SysuiTestCase() { assertThat(latest).hasSize(1) assertThat(latest!![0]).isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) + assertThat((latest!![0] as OngoingActivityChipModel.Active.Timer).startTimeMs) + .isEqualTo(whenElapsed) } @Test @@ -485,14 +615,12 @@ class NotifChipsViewModelTest : SysuiTestCase() { fun chips_noHeadsUp_showsTime() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { - this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 10.minutes.inWholeMilliseconds) } setNotifs( listOf( @@ -517,14 +645,12 @@ class NotifChipsViewModelTest : SysuiTestCase() { fun chips_hasHeadsUpBySystem_showsTime() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { - this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 10.minutes.inWholeMilliseconds) } setNotifs( listOf( @@ -556,22 +682,16 @@ class NotifChipsViewModelTest : SysuiTestCase() { fun chips_hasHeadsUpByUser_forOtherNotif_showsTime() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { - this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 10.minutes.inWholeMilliseconds) } val otherPromotedContentBuilder = PromotedNotificationContentModel.Builder("other notif").apply { - this.time = - PromotedNotificationContentModel.When( - time = 654321L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 10.minutes.inWholeMilliseconds) } val icon = createStatusBarIconViewOrNull() val otherIcon = createStatusBarIconViewOrNull() @@ -610,14 +730,12 @@ class NotifChipsViewModelTest : SysuiTestCase() { fun chips_hasHeadsUpByUser_forThisNotif_onlyShowsIcon() = kosmos.runTest { val latest by collectLastValue(underTest.chips) + val currentTime = 30.minutes.inWholeMilliseconds + fakeSystemClock.setCurrentTimeMillis(currentTime) val promotedContentBuilder = PromotedNotificationContentModel.Builder("notif").apply { - this.time = - PromotedNotificationContentModel.When( - time = 6543L, - mode = PromotedNotificationContentModel.When.Mode.BasicTime, - ) + this.time = When.Time(currentTime + 10.minutes.inWholeMilliseconds) } setNotifs( listOf( @@ -643,11 +761,8 @@ class NotifChipsViewModelTest : SysuiTestCase() { } @Test - @DisableFlags( - FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY, - StatusBarRootModernization.FLAG_NAME, - StatusBarChipsModernization.FLAG_NAME, - ) + @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) + @DisableChipsModernization fun chips_chipsModernizationDisabled_clickingChipNotifiesInteractor() = kosmos.runTest { val latest by collectLastValue(underTest.chips) @@ -675,7 +790,7 @@ class NotifChipsViewModelTest : SysuiTestCase() { @Test @DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY) - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chips_chipsModernizationEnabled_clickingChipNotifiesInteractor() = kosmos.runTest { val latest by collectLastValue(underTest.chips) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt index 6cfad8540491..005af366a6c0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/screenrecord/ui/viewmodel/ScreenRecordChipViewModelTest.kt @@ -17,8 +17,6 @@ package com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel import android.content.DialogInterface -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -44,10 +42,10 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog -import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory -import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.testKosmos import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat @@ -282,7 +280,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_notProjecting_clickListenerShowsDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -299,7 +297,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_projectingEntireScreen_clickListenerShowsDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -317,7 +315,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_projectingSingleTask_clickListenerShowsDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -339,7 +337,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_clickListenerHasCujLegacy() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -359,7 +357,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_recordingState_hasClickBehavior() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -370,7 +368,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_notProjecting_expandActionBehaviorShowsDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -386,7 +384,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_projectingEntireScreen_expandActionBehaviorShowsDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -401,7 +399,7 @@ class ScreenRecordChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_projectingSingleTask_expandActionBehaviorShowsDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt index e708382799c2..d6b10a89726e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/sharetoapp/ui/viewmodel/ShareToAppChipViewModelTest.kt @@ -49,10 +49,10 @@ import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog -import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.mockSystemUIDialogFactory -import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.testKosmos import com.android.systemui.util.time.fakeSystemClock import com.google.common.truth.Truth.assertThat @@ -506,7 +506,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { @Test @EnableFlags(FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP) - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_noScreen_clickListenerShowsGenericShareDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -527,7 +527,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_entireScreen_clickListenerShowsScreenShareDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -548,7 +548,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_singleTask_clickListenerShowsScreenShareDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -573,7 +573,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun chip_clickListenerHasCuj() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -597,7 +597,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_noScreen_hasClickBehavior() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -609,7 +609,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_entireScreen_hasClickBehavior() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -621,7 +621,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_singleTask_hasClickBehavior() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -637,11 +637,8 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags( - FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP, - StatusBarRootModernization.FLAG_NAME, - StatusBarChipsModernization.FLAG_NAME, - ) + @EnableFlags(FLAG_STATUS_BAR_SHOW_AUDIO_ONLY_PROJECTION_CHIP) + @EnableChipsModernization fun chip_noScreen_clickBehaviorShowsGenericShareDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -657,7 +654,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_entireScreen_clickBehaviorShowsScreenShareDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) @@ -673,7 +670,7 @@ class ShareToAppChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun chip_singleTask_clickBehaviorShowsScreenShareDialog() = testScope.runTest { val latest by collectLastValue(underTest.chip) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt index fc3af11c30b3..39b19d3c4191 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModelTest.kt @@ -16,8 +16,6 @@ package com.android.systemui.statusbar.chips.ui.viewmodel -import android.platform.test.annotations.DisableFlags -import android.platform.test.annotations.EnableFlags import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -31,9 +29,9 @@ import com.android.systemui.res.R import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickCallback import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipViewModel.Companion.createDialogLaunchOnClickListener -import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.phone.SystemUIDialog -import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import kotlin.test.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean @@ -64,7 +62,7 @@ class OngoingActivityChipViewModelTest : SysuiTestCase() { mock<Expandable>().apply { whenever(dialogTransitionController(any())).thenReturn(mock()) } @Test - @DisableFlags(StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization fun createDialogLaunchOnClickListener_showsDialogOnClick() { val cuj = DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Test") val clickListener = @@ -82,7 +80,7 @@ class OngoingActivityChipViewModelTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun createDialogLaunchOnClickCallback_showsDialogOnClick() { val cuj = DialogCuj(Cuj.CUJ_STATUS_BAR_LAUNCH_DIALOG_FROM_CHIP, tag = "Test") val clickCallback = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt index 20637cd4af33..2887de38fe23 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt @@ -22,7 +22,6 @@ import android.content.res.Configuration import android.content.res.mainResources import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable -import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.view.View import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -57,7 +56,6 @@ import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsVie import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.getStopActionFromDialog -import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository @@ -66,7 +64,8 @@ import com.android.systemui.statusbar.notification.data.repository.addNotifs import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel import com.android.systemui.statusbar.phone.SystemUIDialog -import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.DisableChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.addOngoingCallState import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.removeOngoingCallState import com.android.systemui.testKosmos @@ -138,7 +137,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(latest).isInstanceOf(OngoingActivityChipModel.Inactive::class.java) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_allHidden_bothPrimaryAndSecondaryHidden() = kosmos.runTest { @@ -155,7 +154,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_allInactive() = kosmos.runTest { @@ -184,7 +183,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertIsScreenRecordChip(latest) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_screenRecordShow_restHidden_primaryIsScreenRecordSecondaryIsHidden() = kosmos.runTest { @@ -201,7 +200,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_screenRecordActive_restInactive() = kosmos.runTest { @@ -230,7 +229,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertIsScreenRecordChip(latest) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_screenRecordShowAndCallShow_primaryIsScreenRecordSecondaryIsCall() = kosmos.runTest { @@ -246,7 +245,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_screenRecordAndCallActive_inThatOrder() = kosmos.runTest { @@ -265,7 +264,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy()) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_oneChip_notSquished() = kosmos.runTest { @@ -278,7 +277,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_oneChip_notSquished() = kosmos.runTest { @@ -291,7 +290,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) } - @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_twoTimerChips_isSmallPortrait_bothSquished() = kosmos.runTest { @@ -307,7 +306,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) } - @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_twoTimerChips_isSmallPortrait_bothSquished() = kosmos.runTest { @@ -323,7 +322,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) } - @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_countdownChipAndTimerChip_countdownNotSquished_butTimerSquished() = kosmos.runTest { @@ -340,7 +339,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) } - @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_countdownChipAndTimerChip_countdownNotSquished_butTimerSquished() = kosmos.runTest { @@ -357,7 +356,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.IconOnly::class.java) } - @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_numberOfChipsChanges_chipsGetSquishedAndUnsquished() = kosmos.runTest { @@ -393,7 +392,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Inactive::class.java) } - @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_numberOfChipsChanges_chipsGetSquishedAndUnsquished() = kosmos.runTest { @@ -425,7 +424,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) } - @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_twoChips_isLandscape_notSquished() = kosmos.runTest { @@ -448,7 +447,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) } - @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_twoChips_isLandscape_notSquished() = kosmos.runTest { @@ -471,7 +470,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) } - @DisableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_twoChips_isLargeScreen_notSquished() = kosmos.runTest { @@ -490,7 +489,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { .isInstanceOf(OngoingActivityChipModel.Active.Timer::class.java) } - @EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_twoChips_isLargeScreen_notSquished() = kosmos.runTest { @@ -522,7 +521,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertIsScreenRecordChip(latest) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_screenRecordShowAndShareToAppShow_primaryIsScreenRecordSecondaryIsHidden() = kosmos.runTest { @@ -542,7 +541,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_screenRecordAndShareToApp_screenRecordIsActiveShareToAppIsInOverflow() = kosmos.runTest { @@ -577,7 +576,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertIsShareToAppChip(latest) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_shareToAppShowAndCallShow_primaryIsShareToAppSecondaryIsCall() = kosmos.runTest { @@ -595,7 +594,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_shareToAppAndCallActive() = kosmos.runTest { @@ -631,7 +630,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertIsCallChip(latest, callNotificationKey) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_onlyCallShown_primaryIsCallSecondaryIsHidden() = kosmos.runTest { @@ -651,7 +650,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_callActive_restInactive() = kosmos.runTest { @@ -671,7 +670,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy()) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_singlePromotedNotif_primaryIsNotifSecondaryIsHidden() = kosmos.runTest { @@ -695,7 +694,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_singlePromotedNotif() = kosmos.runTest { @@ -720,7 +719,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy()) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_twoPromotedNotifs_primaryAndSecondaryAreNotifsInOrder() = kosmos.runTest { @@ -751,7 +750,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_twoPromotedNotifs_bothActiveInOrder() = kosmos.runTest { @@ -785,7 +784,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy()) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_threePromotedNotifs_topTwoShown() = kosmos.runTest { @@ -823,7 +822,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_threePromotedNotifs_topTwoActiveThirdInOverflow() = kosmos.runTest { @@ -865,7 +864,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy()) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_callAndPromotedNotifs_primaryIsCallSecondaryIsNotif() = kosmos.runTest { @@ -898,7 +897,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_callAndPromotedNotifs_callAndFirstNotifActiveSecondNotifInOverflow() = kosmos.runTest { @@ -935,7 +934,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy()) } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_screenRecordAndCallAndPromotedNotifs_notifsNotShown() = kosmos.runTest { @@ -958,7 +957,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_screenRecordAndCallAndPromotedNotif_notifInOverflow() = kosmos.runTest { @@ -1076,7 +1075,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertIsNotifChip(latest, context, notifIcon, "notif") } - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_movesChipsAroundAccordingToPriority() = kosmos.runTest { @@ -1152,7 +1151,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel()) } - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_movesChipsAroundAccordingToPriority() = kosmos.runTest { @@ -1291,7 +1290,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { } /** Regression test for b/347726238. */ - @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @DisableChipsModernization @Test fun chipsLegacy_timerDoesNotResetAfterSubscribersRestart() = kosmos.runTest { @@ -1327,7 +1326,7 @@ class OngoingActivityChipsWithNotifsViewModelTest : SysuiTestCase() { } /** Regression test for b/347726238. */ - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization @Test fun chips_timerDoesNotResetAfterSubscribersRestart() = kosmos.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java index d66b010daefd..a58f7f72f08a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/AssistantFeedbackControllerTest.java @@ -51,8 +51,10 @@ import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.people.NotificationPersonExtractor; import com.android.systemui.util.DeviceConfigProxyFake; +import org.jetbrains.annotations.NotNull; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java index 77fd06757595..8520508c7611 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/DynamicChildBindControllerTest.java @@ -132,7 +132,7 @@ public class DynamicChildBindControllerTest extends SysuiTestCase { LayoutInflater inflater = LayoutInflater.from(mContext); inflater.setFactory2( new RowInflaterTask.RowAsyncLayoutInflater(entry, new FakeSystemClock(), mock( - RowInflaterTaskLogger.class))); + RowInflaterTaskLogger.class), mContext.getUser())); ExpandableNotificationRow row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row, null); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt new file mode 100644 index 000000000000..56cd72e7725f --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimatorTest.kt @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.systemui.statusbar.notification + +import android.util.FloatProperty +import android.util.Property +import android.view.View +import androidx.dynamicanimation.animation.DynamicAnimation +import androidx.test.annotation.UiThreadTest +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.res.R +import com.android.systemui.statusbar.notification.stack.AnimationProperties +import com.android.systemui.statusbar.notification.stack.ViewState +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.kotlin.any + +@SmallTest +@RunWith(AndroidJUnit4::class) +@UiThreadTest +class PhysicsPropertyAnimatorTest : SysuiTestCase() { + private var view: View = View(context) + private val effectiveProperty = + object : FloatProperty<View>("TEST") { + private var _value: Float = 100f + + override fun setValue(view: View, value: Float) { + this._value = value + } + + override fun get(`object`: View): Float { + return _value + } + } + private val property: PhysicsProperty = + PhysicsProperty(R.id.scale_x_animator_tag, effectiveProperty) + private var finishListener: DynamicAnimation.OnAnimationEndListener? = null + private val animationProperties: AnimationProperties = AnimationProperties() + + @Before + fun setUp() { + finishListener = Mockito.mock(DynamicAnimation.OnAnimationEndListener::class.java) + } + + @Test + fun testAnimationStarted() { + PhysicsPropertyAnimator.setProperty( + view, + property, + 200f, + animationProperties, + true, /* animate */ + ) + Assert.assertTrue(PhysicsPropertyAnimator.isAnimating(view, property)) + } + + @Test + fun testNoAnimationStarted() { + PhysicsPropertyAnimator.setProperty(view, property, 200f, animationProperties, false) + Assert.assertFalse(PhysicsPropertyAnimator.isAnimating(view, property)) + } + + @Test + fun testEndValueUpdated() { + PhysicsPropertyAnimator.setProperty( + view, + property, + 200f, + animationProperties, + true, /* animate */ + ) + Assert.assertEquals( + (ViewState.getChildTag(view, property.tag) as PropertyData).finalValue, + 200f, + ) + } + + @Test + fun testOffset() { + effectiveProperty.setValue(view, 100f) + PhysicsPropertyAnimator.setProperty( + view, + property, + 200f, + animationProperties, + true, /* animate */ + ) + val propertyData = ViewState.getChildTag(view, property.tag) as PropertyData + Assert.assertEquals(propertyData.finalValue, 200f) + Assert.assertEquals(propertyData.offset, -100f) + } + + @Test + fun testValueIsSetUnAnimated() { + effectiveProperty.setValue(view, 100f) + PhysicsPropertyAnimator.setProperty( + view, + property, + 200f, + animationProperties, + false, /* animate */ + ) + Assert.assertEquals(200f, effectiveProperty[view]) + } + + @Test + fun testAnimationToRightValueUpdated() { + effectiveProperty.setValue(view, 100f) + PhysicsPropertyAnimator.setProperty( + view, + property, + 200f, + animationProperties, + true, /* animate */ + ) + PhysicsPropertyAnimator.setProperty( + view, + property, + 220f, + animationProperties, + false, /* animate */ + ) + Assert.assertTrue(PhysicsPropertyAnimator.isAnimating(view, property)) + Assert.assertEquals(120f, effectiveProperty[view]) + Assert.assertEquals( + (ViewState.getChildTag(view, property.tag) as PropertyData).finalValue, + 220f, + ) + } + + @Test + fun testAnimationToRightValueUpdateAnimated() { + effectiveProperty.setValue(view, 100f) + PhysicsPropertyAnimator.setProperty( + view, + property, + 200f, + animationProperties, + true, /* animate */ + ) + PhysicsPropertyAnimator.setProperty( + view, + property, + 220f, + animationProperties, + true, /* animate */ + ) + Assert.assertTrue(PhysicsPropertyAnimator.isAnimating(view, property)) + Assert.assertEquals(100f, effectiveProperty[view]) + val propertyData = ViewState.getChildTag(view, property.tag) as PropertyData + Assert.assertEquals(propertyData.finalValue, 220f) + Assert.assertEquals(propertyData.offset, -120f) + } + + @Test + fun testUsingDelay() { + effectiveProperty.setValue(view, 100f) + animationProperties.setDelay(200) + PhysicsPropertyAnimator.setProperty( + view, + property, + 200f, + animationProperties, + true, /* animate */ + ) + val propertyData = ViewState.getChildTag(view, property.tag) as PropertyData + Assert.assertNotNull(propertyData.delayRunnable) + Assert.assertFalse(propertyData.animator?.isRunning ?: true) + } + + @Test + fun testUsingListener() { + PhysicsPropertyAnimator.setProperty( + view, + property, + 200f, + animationProperties, + true, + finishListener, + ) + val propertyData = ViewState.getChildTag(view, property.tag) as PropertyData + propertyData.animator?.cancel() + Mockito.verify(finishListener!!).onAnimationEnd(any(), any(), any(), any()) + } + + @Test + fun testUsingListenerProperties() { + val finishListener2 = Mockito.mock(DynamicAnimation.OnAnimationEndListener::class.java) + val animationProperties: AnimationProperties = + object : AnimationProperties() { + override fun getAnimationEndListener( + property: Property<*, *>? + ): DynamicAnimation.OnAnimationEndListener { + return finishListener2 + } + } + PhysicsPropertyAnimator.setProperty(view, property, 200f, animationProperties, true) + val propertyData = ViewState.getChildTag(view, property.tag) as PropertyData + propertyData.animator?.cancel() + Mockito.verify(finishListener2).onAnimationEnd(any(), any(), any(), any()) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt new file mode 100644 index 000000000000..83e26c4220b1 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.collection + +import android.app.Notification +import android.graphics.Color +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule +import android.testing.TestableLooper.RunWithLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +@RunWithLooper +class BundleEntryTest : SysuiTestCase() { + private lateinit var underTest: BundleEntry + + @get:Rule + val setFlagsRule = SetFlagsRule() + + @Before + fun setUp() { + underTest = BundleEntry("key") + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getParent_adapter() { + assertThat(underTest.entryAdapter.parent).isEqualTo(GroupEntry.ROOT_ENTRY) + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun isTopLevelEntry_adapter() { + assertThat(underTest.entryAdapter.isTopLevelEntry).isTrue() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getRow_adapter() { + assertThat(underTest.entryAdapter.row).isNull() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getGroupRoot_adapter() { + assertThat(underTest.entryAdapter.groupRoot).isEqualTo(underTest.entryAdapter) + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getKey_adapter() { + assertThat(underTest.entryAdapter.key).isEqualTo("key") + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun isClearable_adapter() { + assertThat(underTest.entryAdapter.isClearable).isTrue() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getSummarization_adapter() { + assertThat(underTest.entryAdapter.summarization).isNull() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getContrastedColor_adapter() { + assertThat(underTest.entryAdapter.getContrastedColor(context, false, Color.WHITE)) + .isEqualTo(Notification.COLOR_DEFAULT) + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun canPeek_adapter() { + assertThat(underTest.entryAdapter.canPeek()).isFalse() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getWhen_adapter() { + assertThat(underTest.entryAdapter.`when`).isEqualTo(0) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java index 8e95ac599ce1..76e2d619a4df 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java @@ -30,6 +30,9 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.app.NotificationChannel; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -39,8 +42,10 @@ import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -57,6 +62,9 @@ public class HighPriorityProviderTest extends SysuiTestCase { @Mock private GroupMembershipManager mGroupMembershipManager; private HighPriorityProvider mHighPriorityProvider; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -210,6 +218,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) public void testIsHighPriority_checkChildrenToCalculatePriority_legacy() { // GIVEN: a summary with low priority has a highPriorityChild and a lowPriorityChild final NotificationEntry summary = createNotifEntry(false); @@ -247,20 +256,18 @@ public class HighPriorityProviderTest extends SysuiTestCase { } @Test - public void testIsHighPriority_checkChildrenToCalculatePriority() { + public void testIsHighPriority_checkChildrenViewsToCalculatePriority() { // GIVEN: // parent with summary = lowPrioritySummary // NotificationEntry = lowPriorityChild // NotificationEntry = highPriorityChild + List<NotificationEntry> children = List.of(createNotifEntry(false), createNotifEntry(true)); final NotificationEntry lowPrioritySummary = createNotifEntry(false); final GroupEntry parentEntry = new GroupEntryBuilder() .setSummary(lowPrioritySummary) + .setChildren(children) .build(); - when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn( - new ArrayList<>( - List.of( - createNotifEntry(false), - createNotifEntry(true)))); + when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn(children); // THEN the GroupEntry parentEntry is high priority since it has a high priority child assertTrue(mHighPriorityProvider.isHighPriority(parentEntry)); @@ -272,10 +279,11 @@ public class HighPriorityProviderTest extends SysuiTestCase { // parent with summary = lowPrioritySummary // NotificationEntry = lowPriorityChild final NotificationEntry lowPrioritySummary = createNotifEntry(false); + final NotificationEntry lowPriorityChild = createNotifEntry(false); final GroupEntry parentEntry = new GroupEntryBuilder() .setSummary(lowPrioritySummary) + .setChildren(List.of(lowPriorityChild)) .build(); - final NotificationEntry lowPriorityChild = createNotifEntry(false); when(mGroupMembershipManager.getChildren(parentEntry)).thenReturn( new ArrayList<>(List.of(lowPriorityChild))); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java index 281ce16b539f..1f5c6722f38e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java @@ -28,6 +28,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking; import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -46,6 +48,7 @@ import android.os.Bundle; import android.os.UserHandle; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; @@ -59,9 +62,12 @@ import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -83,6 +89,9 @@ public class NotificationEntryTest extends SysuiTestCase { private NotificationChannel mChannel = Mockito.mock(NotificationChannel.class); private final FakeSystemClock mClock = new FakeSystemClock(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Before public void setup() { Notification.Builder n = new Notification.Builder(mContext, "") @@ -154,9 +163,10 @@ public class NotificationEntryTest extends SysuiTestCase { @Test public void testIsExemptFromDndVisualSuppression_media() { + MediaSession session = new MediaSession(mContext, "test"); Notification.Builder n = new Notification.Builder(mContext, "") .setStyle(new Notification.MediaStyle() - .setMediaSession(mock(MediaSession.Token.class))) + .setMediaSession(session.getSessionToken())) .setSmallIcon(R.drawable.ic_person) .setContentTitle("Title") .setContentText("Text"); @@ -444,6 +454,215 @@ public class NotificationEntryTest extends SysuiTestCase { // no crash, good } + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void getParent_adapter() { + GroupEntry ge = new GroupEntryBuilder() + .build(); + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .setParent(ge) + .build(); + + assertThat(entry.getEntryAdapter().getParent()).isEqualTo(entry.getParent()); + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void isTopLevelEntry_adapter() { + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .setParent(GroupEntry.ROOT_ENTRY) + .build(); + + assertThat(entry.getEntryAdapter().isTopLevelEntry()).isTrue(); + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void getKey_adapter() { + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + + assertThat(entry.getEntryAdapter().getKey()).isEqualTo(entry.getKey()); + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void getRow_adapter() { + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + entry.setRow(row); + + assertThat(entry.getEntryAdapter().getRow()).isEqualTo(entry.getRow()); + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void getGroupRoot_adapter_groupSummary() { + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setGroupSummary(true) + .setGroup("key") + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .setParent(GroupEntry.ROOT_ENTRY) + .build(); + entry.setRow(row); + + assertThat(entry.getEntryAdapter().getGroupRoot()).isNull(); + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void getGroupRoot_adapter_groupChild() { + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setGroupSummary(true) + .setGroup("key") + .build(); + + NotificationEntry parent = new NotificationEntryBuilder() + .setParent(GroupEntry.ROOT_ENTRY) + .build(); + GroupEntryBuilder groupEntry = new GroupEntryBuilder() + .setSummary(parent); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .setParent(groupEntry.build()) + .build(); + + assertThat(entry.getEntryAdapter().getGroupRoot()).isEqualTo(parent.getEntryAdapter()); + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void isClearable_adapter() { + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + entry.setRow(row); + + assertThat(entry.getEntryAdapter().isClearable()).isEqualTo(entry.isClearable()); + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void getSummarization_adapter() { + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + Ranking ranking = new RankingBuilder(entry.getRanking()) + .setSummarization("hello") + .build(); + entry.setRanking(ranking); + entry.setRow(row); + + assertThat(entry.getEntryAdapter().getSummarization()).isEqualTo("hello"); + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void getIcons_adapter() { + ExpandableNotificationRow row = mock(ExpandableNotificationRow.class); + Notification notification = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .build(); + + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setChannel(mChannel) + .setId(mId++) + .setNotification(notification) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + entry.setRow(row); + + assertThat(entry.getEntryAdapter().getIcons()).isEqualTo(entry.getIcons()); + } private Notification.Action createContextualAction(String title) { return new Notification.Action.Builder( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt index e93c74252251..7fa157fa7cb3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinatorTest.kt @@ -27,14 +27,29 @@ import android.testing.TestableLooper.RunWithLooper import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor +import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips +import com.android.systemui.statusbar.core.StatusBarRootModernization +import com.android.systemui.statusbar.notification.buildNotificationEntry +import com.android.systemui.statusbar.notification.buildOngoingCallEntry +import com.android.systemui.statusbar.notification.buildPromotedOngoingEntry import com.android.systemui.statusbar.notification.collection.buildEntry import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner import com.android.systemui.statusbar.notification.collection.notifPipeline +import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi +import com.android.systemui.statusbar.notification.promoted.domain.interactor.promotedNotificationsInteractor +import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.testKosmos import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before @@ -59,7 +74,13 @@ class ColorizedFgsCoordinatorTest : SysuiTestCase() { fun setup() { allowTestableLooperAsMainThread() - colorizedFgsCoordinator = ColorizedFgsCoordinator() + kosmos.statusBarNotificationChipsInteractor.start() + + colorizedFgsCoordinator = + ColorizedFgsCoordinator( + kosmos.applicationCoroutineScope, + kosmos.promotedNotificationsInteractor, + ) colorizedFgsCoordinator.attach(notifPipeline) sectioner = colorizedFgsCoordinator.sectioner } @@ -178,6 +199,37 @@ class ColorizedFgsCoordinatorTest : SysuiTestCase() { verify(notifPipeline, never()).addPromoter(any()) } + @Test + @EnableFlags( + PromotedNotificationUi.FLAG_NAME, + StatusBarNotifChips.FLAG_NAME, + StatusBarChipsModernization.FLAG_NAME, + StatusBarRootModernization.FLAG_NAME, + ) + fun comparatorPutsCallBeforeOther() = + kosmos.runTest { + // GIVEN a call and a promoted ongoing notification + val callEntry = buildOngoingCallEntry(promoted = false) + val ronEntry = buildPromotedOngoingEntry() + val otherEntry = buildNotificationEntry(tag = "other") + + kosmos.renderNotificationListInteractor.setRenderedList( + listOf(callEntry, ronEntry, otherEntry) + ) + + val orderedChipNotificationKeys by + collectLastValue(kosmos.promotedNotificationsInteractor.orderedChipNotificationKeys) + + // THEN the order of the notification keys should be the call then the RON + assertThat(orderedChipNotificationKeys) + .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") + + // VERIFY that the comparator puts the call before the ron + assertThat(sectioner.comparator!!.compare(callEntry, ronEntry)).isLessThan(0) + // VERIFY that the comparator puts the ron before the other + assertThat(sectioner.comparator!!.compare(ronEntry, otherEntry)).isLessThan(0) + } + private fun makeCallStyle(): Notification.CallStyle { val pendingIntent = PendingIntent.getBroadcast(mContext, 0, Intent("action"), PendingIntent.FLAG_IMMUTABLE) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt index 7781df1ad91f..43cb9575b609 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/OriginalUnseenKeyguardCoordinatorTest.kt @@ -16,8 +16,11 @@ package com.android.systemui.statusbar.notification.collection.coordinator import android.app.Notification +import android.app.Notification.MediaStyle +import android.media.session.MediaSession import android.platform.test.flag.junit.FlagsParameterization import android.provider.Settings +import android.service.notification.StatusBarNotification import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.dumpManager @@ -36,6 +39,7 @@ import com.android.systemui.scene.data.repository.Idle import com.android.systemui.scene.data.repository.setTransition import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.statusbar.SbnBuilder import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder @@ -217,6 +221,16 @@ class OriginalUnseenKeyguardCoordinatorTest(flags: FlagsParameterization) : Sysu mock<ExpandableNotificationRow>().apply { whenever(isMediaRow).thenReturn(true) } + sbn = SbnBuilder().setNotification( + Notification.Builder(context, "channel").setStyle( + MediaStyle().setMediaSession( + MediaSession( + context, + "tag" + ).sessionToken + ) + ).build() + ).build() } collectionListener.onEntryAdded(fakeEntry) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt index db5921d8bd36..3dd0982ba2ff 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt @@ -17,23 +17,29 @@ package com.android.systemui.statusbar.notification.collection.render import android.os.Build +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.log.assertLogsWtf +import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder import com.android.systemui.statusbar.notification.collection.ListEntry import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import org.junit.Assume import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.never @@ -44,6 +50,9 @@ import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidJUnit4::class) class GroupExpansionManagerTest : SysuiTestCase() { + @get:Rule + val setFlagsRule = SetFlagsRule() + private lateinit var underTest: GroupExpansionManagerImpl private val dumpManager: DumpManager = mock() @@ -52,8 +61,8 @@ class GroupExpansionManagerTest : SysuiTestCase() { private val pipeline: NotifPipeline = mock() private lateinit var beforeRenderListListener: OnBeforeRenderListListener - private val summary1 = notificationEntry("foo", 1) - private val summary2 = notificationEntry("bar", 1) + private val summary1 = notificationSummaryEntry("foo", 1) + private val summary2 = notificationSummaryEntry("bar", 1) private val entries = listOf<ListEntry>( GroupEntryBuilder() @@ -82,15 +91,25 @@ class GroupExpansionManagerTest : SysuiTestCase() { private fun notificationEntry(pkg: String, id: Int) = NotificationEntryBuilder().setPkg(pkg).setId(id).build().apply { row = mock() } + private fun notificationSummaryEntry(pkg: String, id: Int) = + NotificationEntryBuilder().setPkg(pkg).setId(id).setParent(GroupEntry.ROOT_ENTRY).build() + .apply { row = mock() } + @Before fun setUp() { whenever(groupMembershipManager.getGroupSummary(summary1)).thenReturn(summary1) whenever(groupMembershipManager.getGroupSummary(summary2)).thenReturn(summary2) + whenever(groupMembershipManager.getGroupRoot(summary1.entryAdapter)) + .thenReturn(summary1.entryAdapter) + whenever(groupMembershipManager.getGroupRoot(summary2.entryAdapter)) + .thenReturn(summary2.entryAdapter) + underTest = GroupExpansionManagerImpl(dumpManager, groupMembershipManager) } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun notifyOnlyOnChange() { var listenerCalledCount = 0 underTest.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ } @@ -108,6 +127,25 @@ class GroupExpansionManagerTest : SysuiTestCase() { } @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun notifyOnlyOnChange_withEntryAdapter() { + var listenerCalledCount = 0 + underTest.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ } + + underTest.setGroupExpanded(summary1.entryAdapter, false) + assertThat(listenerCalledCount).isEqualTo(0) + underTest.setGroupExpanded(summary1.entryAdapter, true) + assertThat(listenerCalledCount).isEqualTo(1) + underTest.setGroupExpanded(summary2.entryAdapter, true) + assertThat(listenerCalledCount).isEqualTo(2) + underTest.setGroupExpanded(summary1.entryAdapter, true) + assertThat(listenerCalledCount).isEqualTo(2) + underTest.setGroupExpanded(summary2.entryAdapter, false) + assertThat(listenerCalledCount).isEqualTo(3) + } + + @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun expandUnattachedEntry() { // First, expand the entry when it is attached. underTest.setGroupExpanded(summary1, true) @@ -122,6 +160,22 @@ class GroupExpansionManagerTest : SysuiTestCase() { } @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun expandUnattachedEntryAdapter() { + // First, expand the entry when it is attached. + underTest.setGroupExpanded(summary1.entryAdapter, true) + assertThat(underTest.isGroupExpanded(summary1.entryAdapter)).isTrue() + + // Un-attach it, and un-expand it. + NotificationEntryBuilder.setNewParent(summary1, null) + underTest.setGroupExpanded(summary1.entryAdapter, false) + + // Expanding again should throw. + assertLogsWtf { underTest.setGroupExpanded(summary1.entryAdapter, true) } + } + + @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun syncWithPipeline() { underTest.attach(pipeline) beforeRenderListListener = withArgCaptor { @@ -143,4 +197,28 @@ class GroupExpansionManagerTest : SysuiTestCase() { verify(listener).onGroupExpansionChange(summary1.row, false) verifyNoMoreInteractions(listener) } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun syncWithPipeline_withEntryAdapter() { + underTest.attach(pipeline) + beforeRenderListListener = withArgCaptor { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + val listener: OnGroupExpansionChangeListener = mock() + underTest.registerGroupExpansionChangeListener(listener) + + beforeRenderListListener.onBeforeRenderList(entries) + verify(listener, never()).onGroupExpansionChange(any(), any()) + + // Expand one of the groups. + underTest.setGroupExpanded(summary1.entryAdapter, true) + verify(listener).onGroupExpansionChange(summary1.row, true) + + // Empty the pipeline list and verify that the group is no longer expanded. + beforeRenderListListener.onBeforeRenderList(emptyList()) + verify(listener).onGroupExpansionChange(summary1.row, false) + verifyNoMoreInteractions(listener) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt index 2cbcc5a8d925..dcbf44e6e301 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt @@ -16,34 +16,46 @@ package com.android.systemui.statusbar.notification.collection.render +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.google.common.truth.Truth.assertThat +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class GroupMembershipManagerTest : SysuiTestCase() { + + @get:Rule + val setFlagsRule = SetFlagsRule() + private var underTest = GroupMembershipManagerImpl() @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun isChildInGroup_topLevel() { val topLevelEntry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build() assertThat(underTest.isChildInGroup(topLevelEntry)).isFalse() } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun isChildInGroup_noParent() { val noParentEntry = NotificationEntryBuilder().setParent(null).build() assertThat(underTest.isChildInGroup(noParentEntry)).isFalse() } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun isChildInGroup_summary() { val groupKey = "group" val summary = @@ -57,12 +69,14 @@ class GroupMembershipManagerTest : SysuiTestCase() { } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun isGroupSummary_topLevelEntry() { val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build() assertThat(underTest.isGroupSummary(entry)).isFalse() } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun isGroupSummary_summary() { val groupKey = "group" val summary = @@ -76,6 +90,7 @@ class GroupMembershipManagerTest : SysuiTestCase() { } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun isGroupSummary_child() { val groupKey = "group" val summary = @@ -90,12 +105,14 @@ class GroupMembershipManagerTest : SysuiTestCase() { } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun getGroupSummary_topLevelEntry() { val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build() assertThat(underTest.getGroupSummary(entry)).isNull() } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun getGroupSummary_summary() { val groupKey = "group" val summary = @@ -109,6 +126,7 @@ class GroupMembershipManagerTest : SysuiTestCase() { } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) fun getGroupSummary_child() { val groupKey = "group" val summary = @@ -121,4 +139,104 @@ class GroupMembershipManagerTest : SysuiTestCase() { assertThat(underTest.getGroupSummary(entry)).isEqualTo(summary) } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun isChildEntryAdapterInGroup_topLevel() { + val topLevelEntry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build() + assertThat(underTest.isChildInGroup(topLevelEntry.entryAdapter)).isFalse() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun isChildEntryAdapterInGroup_noParent() { + val noParentEntry = NotificationEntryBuilder().setParent(null).build() + assertThat(underTest.isChildInGroup(noParentEntry.entryAdapter)).isFalse() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun isChildEntryAdapterInGroup_summary() { + val groupKey = "group" + val summary = + NotificationEntryBuilder() + .setGroup(mContext, groupKey) + .setGroupSummary(mContext, true) + .build() + GroupEntryBuilder().setKey(groupKey).setSummary(summary).build() + + assertThat(underTest.isChildInGroup(summary.entryAdapter)).isFalse() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun isGroupRoot_topLevelEntry() { + val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build() + assertThat(underTest.isGroupRoot(entry.entryAdapter)).isFalse() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun isGroupRoot_summary() { + val groupKey = "group" + val summary = + NotificationEntryBuilder() + .setGroup(mContext, groupKey) + .setGroupSummary(mContext, true) + .build() + GroupEntryBuilder().setKey(groupKey).setSummary(summary).build() + + assertThat(underTest.isGroupRoot(summary.entryAdapter)).isTrue() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun isGroupRoot_child() { + val groupKey = "group" + val summary = + NotificationEntryBuilder() + .setGroup(mContext, groupKey) + .setGroupSummary(mContext, true) + .build() + val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build() + GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build() + + assertThat(underTest.isGroupRoot(entry.entryAdapter)).isFalse() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getGroupRoot_topLevelEntry() { + val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build() + assertThat(underTest.getGroupRoot(entry.entryAdapter)).isNull() + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getGroupRoot_summary() { + val groupKey = "group" + val summary = + NotificationEntryBuilder() + .setGroup(mContext, groupKey) + .setGroupSummary(mContext, true) + .build() + GroupEntryBuilder().setKey(groupKey).setSummary(summary).build() + + assertThat(underTest.getGroupRoot(summary.entryAdapter)).isEqualTo(summary.entryAdapter) + } + + @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + fun getGroupRoot_child() { + val groupKey = "group" + val summary = + NotificationEntryBuilder() + .setGroup(mContext, groupKey) + .setGroupSummary(mContext, true) + .build() + val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build() + GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build() + + assertThat(underTest.getGroupRoot(entry.entryAdapter)).isEqualTo(summary.entryAdapter) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt index 339f8fac3820..e22acd53e584 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImplTest.kt @@ -106,11 +106,15 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() { this.addOverride(R.integer.touch_acceptance_delay, TEST_TOUCH_ACCEPTANCE_TIME) this.addOverride( R.integer.heads_up_notification_minimum_time, - TEST_MINIMUM_DISPLAY_TIME, + TEST_MINIMUM_DISPLAY_TIME_DEFAULT, ) this.addOverride( R.integer.heads_up_notification_minimum_time_with_throttling, - TEST_MINIMUM_DISPLAY_TIME, + TEST_MINIMUM_DISPLAY_TIME_DEFAULT, + ) + this.addOverride( + R.integer.heads_up_notification_minimum_time_for_user_initiated, + TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED, ) this.addOverride(R.integer.heads_up_notification_decay, TEST_AUTO_DISMISS_TIME) this.addOverride( @@ -414,7 +418,7 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test - fun testRemoveNotification_beforeMinimumDisplayTime() { + fun testRemoveNotification_beforeMinimumDisplayTime_notUserInitiatedHun() { val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) useAccessibilityTimeout(false) @@ -429,18 +433,22 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() { assertThat(removedImmediately).isFalse() assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() - systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong()) + systemClock.advanceTime( + ((TEST_MINIMUM_DISPLAY_TIME_DEFAULT + TEST_AUTO_DISMISS_TIME) / 2).toLong() + ) assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() } @Test - fun testRemoveNotification_afterMinimumDisplayTime() { + fun testRemoveNotification_afterMinimumDisplayTime_notUserInitiatedHun() { val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) useAccessibilityTimeout(false) underTest.showNotification(entry) - systemClock.advanceTime(((TEST_MINIMUM_DISPLAY_TIME + TEST_AUTO_DISMISS_TIME) / 2).toLong()) + systemClock.advanceTime( + ((TEST_MINIMUM_DISPLAY_TIME_DEFAULT + TEST_AUTO_DISMISS_TIME) / 2).toLong() + ) assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() @@ -455,6 +463,57 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test + @EnableFlags(StatusBarNotifChips.FLAG_NAME) + fun testRemoveNotification_beforeMinimumDisplayTime_forUserInitiatedHun() { + useAccessibilityTimeout(false) + + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + entry.row = testHelper.createRow() + underTest.showNotification(entry, isPinnedByUser = true) + + val removedImmediately = + underTest.removeNotification( + entry.key, + /* releaseImmediately = */ false, + "beforeMinimumDisplayTime", + ) + assertThat(removedImmediately).isFalse() + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + + systemClock.advanceTime( + ((TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED + TEST_AUTO_DISMISS_TIME) / 2).toLong() + ) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() + } + + @Test + @EnableFlags(StatusBarNotifChips.FLAG_NAME) + fun testRemoveNotification_afterMinimumDisplayTime_forUserInitiatedHun() { + useAccessibilityTimeout(false) + + val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) + entry.row = testHelper.createRow() + underTest.showNotification(entry, isPinnedByUser = true) + + systemClock.advanceTime( + ((TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED + TEST_AUTO_DISMISS_TIME) / 2).toLong() + ) + + assertThat(underTest.isHeadsUpEntry(entry.key)).isTrue() + + val removedImmediately = + underTest.removeNotification( + entry.key, + /* releaseImmediately = */ false, + "afterMinimumDisplayTime", + ) + + assertThat(removedImmediately).isTrue() + assertThat(underTest.isHeadsUpEntry(entry.key)).isFalse() + } + + @Test fun testRemoveNotification_releaseImmediately() { val entry = HeadsUpManagerTestUtil.createEntry(/* id= */ 0, mContext) @@ -1047,16 +1106,21 @@ class HeadsUpManagerImplTest(flags: FlagsParameterization) : SysuiTestCase() { } companion object { - const val TEST_TOUCH_ACCEPTANCE_TIME = 200 - const val TEST_A11Y_AUTO_DISMISS_TIME = 1000 - const val TEST_EXTENSION_TIME = 500 + private const val TEST_TOUCH_ACCEPTANCE_TIME = 200 + private const val TEST_A11Y_AUTO_DISMISS_TIME = 1000 + private const val TEST_EXTENSION_TIME = 500 - const val TEST_MINIMUM_DISPLAY_TIME = 400 - const val TEST_AUTO_DISMISS_TIME = 600 - const val TEST_STICKY_AUTO_DISMISS_TIME = 800 + private const val TEST_MINIMUM_DISPLAY_TIME_DEFAULT = 400 + private const val TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED = 500 + private const val TEST_AUTO_DISMISS_TIME = 600 + private const val TEST_STICKY_AUTO_DISMISS_TIME = 800 init { - assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME) + assertThat(TEST_MINIMUM_DISPLAY_TIME_DEFAULT) + .isLessThan(TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED) + assertThat(TEST_MINIMUM_DISPLAY_TIME_DEFAULT).isLessThan(TEST_AUTO_DISMISS_TIME) + assertThat(TEST_MINIMUM_DISPLAY_TIME_FOR_USER_INITIATED) + .isLessThan(TEST_AUTO_DISMISS_TIME) assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME) assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierTest.kt new file mode 100644 index 000000000000..75f5de0118d4 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierTest.kt @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.people + +import android.app.Notification +import android.app.NotificationChannel +import android.content.pm.ShortcutInfo +import android.service.notification.NotificationListenerService.Ranking +import android.service.notification.StatusBarNotification +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.statusbar.RankingBuilder +import com.android.systemui.statusbar.notification.collection.GroupEntry +import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_FULL_PERSON +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON +import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.Mockito.mock + + +@SmallTest +@RunWith(AndroidJUnit4::class) +class PeopleNotificationIdentifierTest : SysuiTestCase() { + + private lateinit var underTest: PeopleNotificationIdentifierImpl + + private val summary1 = notificationEntry("foo", 1, summary = true) + private val summary2 = notificationEntry("bar", 1, summary = true) + private val entries = + listOf<GroupEntry>( + GroupEntryBuilder() + .setSummary(summary1) + .setChildren( + listOf( + notificationEntry("foo", 2), + notificationEntry("foo", 3), + notificationEntry("foo", 4) + ) + ) + .build(), + GroupEntryBuilder() + .setSummary(summary2) + .setChildren( + listOf( + notificationEntry("bar", 2), + notificationEntry("bar", 3), + notificationEntry("bar", 4) + ) + ) + .build() + ) + + private fun notificationEntry( + pkg: String, + id: Int, + summary: Boolean = false + ): NotificationEntry { + val sbn = mock(StatusBarNotification::class.java) + Mockito.`when`(sbn.key).thenReturn("key") + Mockito.`when`(sbn.notification).thenReturn(mock(Notification::class.java)) + if (summary) + Mockito.`when`(sbn.notification.isGroupSummary).thenReturn(true) + return NotificationEntryBuilder().setPkg(pkg) + .setId(id) + .setSbn(sbn) + .build().apply { + row = mock(ExpandableNotificationRow::class.java) + } + } + + private fun personRanking(entry: NotificationEntry, personType: Int): Ranking { + val channel = NotificationChannel("person", "person", 4) + channel.setConversationId("parent", "person") + channel.setImportantConversation(true) + + val br = RankingBuilder(entry.ranking) + + when (personType) { + TYPE_NON_PERSON -> br.setIsConversation(false) + TYPE_PERSON -> { + br.setIsConversation(true) + br.setShortcutInfo(null) + } + + TYPE_IMPORTANT_PERSON -> { + br.setIsConversation(true) + br.setShortcutInfo(mock(ShortcutInfo::class.java)) + br.setChannel(channel) + } + + else -> { + br.setIsConversation(true) + br.setShortcutInfo(mock(ShortcutInfo::class.java)) + } + } + + return br.build() + } + + @Before + fun setUp() { + val personExtractor = object : NotificationPersonExtractor { + public override fun isPersonNotification(sbn: StatusBarNotification): Boolean { + return true + } + } + + underTest = PeopleNotificationIdentifierImpl( + personExtractor, + GroupMembershipManagerImpl() + ) + } + + private val Ranking.personTypeInfo + get() = when { + !isConversation -> TYPE_NON_PERSON + conversationShortcutInfo == null -> TYPE_PERSON + channel?.isImportantConversation == true -> TYPE_IMPORTANT_PERSON + else -> TYPE_FULL_PERSON + } + + @Test + fun getPeopleNotificationType_entryIsImportant() { + summary1.setRanking(personRanking(summary1, TYPE_IMPORTANT_PERSON)) + + assertThat(underTest.getPeopleNotificationType(summary1)).isEqualTo(TYPE_IMPORTANT_PERSON) + } + + @Test + fun getPeopleNotificationType_importantChild() { + entries.get(0).getChildren().get(0).setRanking( + personRanking(entries.get(0).getChildren().get(0), TYPE_IMPORTANT_PERSON) + ) + + assertThat(entries.get(0).summary?.let { underTest.getPeopleNotificationType(it) }) + .isEqualTo(TYPE_IMPORTANT_PERSON) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt index a3fde5a06573..216fd2d54a1e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt @@ -39,18 +39,24 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB import com.android.systemui.statusbar.notification.promoted.AutomaticPromotionCoordinator.Companion.EXTRA_WAS_AUTOMATICALLY_PROMOTED import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.When import com.android.systemui.statusbar.notification.row.RowImageInflater import com.android.systemui.testKosmos +import com.android.systemui.util.time.fakeSystemClock +import com.android.systemui.util.time.systemClock import com.google.common.truth.Truth.assertThat +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { - private val kosmos = testKosmos() + private val kosmos = testKosmos().apply { systemClock = fakeSystemClock } private val underTest = kosmos.promotedNotificationContentExtractor + private val systemClock = kosmos.fakeSystemClock private val rowImageInflater = RowImageInflater.newInstance(previousIndex = null) private val imageModelProvider by lazy { rowImageInflater.useForContentModel() } @@ -177,7 +183,176 @@ class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) - fun extractsContent_fromBaseStyle() { + fun extractTime_none() { + assertExtractedTime(hasTime = false, hasChronometer = false, expected = ExpectedTime.Null) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_basicTimeNow() { + assertExtractedTime( + hasTime = true, + hasChronometer = false, + whenOffset = Duration.ZERO, + expected = ExpectedTime.Time, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_basicTimePast() { + assertExtractedTime( + hasTime = true, + hasChronometer = false, + whenOffset = (-5).minutes, + expected = ExpectedTime.Time, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_basicTimeFuture() { + assertExtractedTime( + hasTime = true, + hasChronometer = false, + whenOffset = 5.minutes, + expected = ExpectedTime.Time, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_countUpNow() { + assertExtractedTime( + hasTime = false, + hasChronometer = true, + isCountDown = false, + whenOffset = Duration.ZERO, + expected = ExpectedTime.CountUp, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_countUpPast() { + assertExtractedTime( + hasTime = false, + hasChronometer = true, + isCountDown = false, + whenOffset = (-5).minutes, + expected = ExpectedTime.CountUp, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_countUpFuture() { + assertExtractedTime( + hasTime = false, + hasChronometer = true, + isCountDown = false, + whenOffset = 5.minutes, + expected = ExpectedTime.CountUp, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_countDownNow() { + assertExtractedTime( + hasTime = false, + hasChronometer = true, + isCountDown = true, + whenOffset = Duration.ZERO, + expected = ExpectedTime.CountDown, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_countDownPast() { + assertExtractedTime( + hasTime = false, + hasChronometer = true, + isCountDown = true, + whenOffset = (-5).minutes, + expected = ExpectedTime.CountDown, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_countDownFuture() { + assertExtractedTime( + hasTime = false, + hasChronometer = true, + isCountDown = true, + whenOffset = 5.minutes, + expected = ExpectedTime.CountDown, + ) + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractTime_prefersChronometerToWhen() { + assertExtractedTime(hasTime = true, hasChronometer = true, expected = ExpectedTime.CountUp) + } + + private enum class ExpectedTime { + Null, + Time, + CountUp, + CountDown, + } + + private fun assertExtractedTime( + hasTime: Boolean = false, + hasChronometer: Boolean = false, + isCountDown: Boolean = false, + whenOffset: Duration = Duration.ZERO, + expected: ExpectedTime, + ) { + // Set the two timebases to different (arbitrary) numbers, so we can verify whether the + // extractor is doing the timebase adjustment correctly. + systemClock.setCurrentTimeMillis(1_739_570_992_579L) + systemClock.setElapsedRealtime(1_380_967_080L) + + val whenCurrentTime = systemClock.currentTimeMillis() + whenOffset.inWholeMilliseconds + val whenElapsedRealtime = systemClock.elapsedRealtime() + whenOffset.inWholeMilliseconds + + val entry = createEntry { + setShowWhen(hasTime) + setUsesChronometer(hasChronometer) + setChronometerCountDown(isCountDown) + setWhen(whenCurrentTime) + } + + val content = extractContent(entry) + + assertThat(content).isNotNull() + + when (expected) { + ExpectedTime.Null -> assertThat(content?.time).isNull() + + ExpectedTime.Time -> { + val actual = content?.time as? When.Time + assertThat(actual).isNotNull() + assertThat(actual?.currentTimeMillis).isEqualTo(whenCurrentTime) + } + + ExpectedTime.CountDown, + ExpectedTime.CountUp -> { + val actual = content?.time as? When.Chronometer + assertThat(actual).isNotNull() + assertThat(actual?.elapsedRealtimeMillis).isEqualTo(whenElapsedRealtime) + assertThat(actual?.isCountDown).isEqualTo(expected == ExpectedTime.CountDown) + } + } + } + + @Test + @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) + fun extractContent_fromBaseStyle() { val entry = createEntry { setStyle(null) } val content = extractContent(entry) @@ -188,7 +363,7 @@ class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) - fun extractsContent_fromBigPictureStyle() { + fun extractContent_fromBigPictureStyle() { val entry = createEntry { setStyle(BigPictureStyle()) } val content = extractContent(entry) @@ -261,7 +436,7 @@ class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) - fun extractsContent_fromOldProgressDeterminate() { + fun extractContent_fromOldProgressDeterminate() { val entry = createEntry { setProgress(TEST_PROGRESS_MAX, TEST_PROGRESS, /* indeterminate= */ false) } @@ -282,7 +457,7 @@ class PromotedNotificationContentExtractorImplTest : SysuiTestCase() { @Test @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME) - fun extractsContent_fromOldProgressIndeterminate() { + fun extractContent_fromOldProgressIndeterminate() { val entry = createEntry { setProgress(TEST_PROGRESS_MAX, TEST_PROGRESS, /* indeterminate= */ true) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt new file mode 100644 index 000000000000..aa6e76d08c17 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.promoted.domain.interactor + +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor +import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips +import com.android.systemui.statusbar.core.StatusBarRootModernization +import com.android.systemui.statusbar.notification.buildNotificationEntry +import com.android.systemui.statusbar.notification.buildOngoingCallEntry +import com.android.systemui.statusbar.notification.buildPromotedOngoingEntry +import com.android.systemui.statusbar.notification.domain.interactor.renderNotificationListInteractor +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi +import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +@EnableFlags( + PromotedNotificationUi.FLAG_NAME, + StatusBarNotifChips.FLAG_NAME, + StatusBarChipsModernization.FLAG_NAME, + StatusBarRootModernization.FLAG_NAME, +) +class PromotedNotificationsInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + + private val Kosmos.underTest by Fixture { promotedNotificationsInteractor } + + @Before + fun setUp() { + kosmos.statusBarNotificationChipsInteractor.start() + } + + @Test + fun orderedChipNotificationKeys_containsNonPromotedCalls() = + kosmos.runTest { + // GIVEN a call and a promoted ongoing notification + val callEntry = buildOngoingCallEntry(promoted = false) + val ronEntry = buildPromotedOngoingEntry() + val otherEntry = buildNotificationEntry(tag = "other") + + renderNotificationListInteractor.setRenderedList( + listOf(callEntry, ronEntry, otherEntry) + ) + + val orderedChipNotificationKeys by + collectLastValue(underTest.orderedChipNotificationKeys) + + // THEN the order of the notification keys should be the call then the RON + assertThat(orderedChipNotificationKeys) + .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") + } + + @Test + fun orderedChipNotificationKeys_containsPromotedCalls() = + kosmos.runTest { + // GIVEN a call and a promoted ongoing notification + val callEntry = buildOngoingCallEntry(promoted = true) + val ronEntry = buildPromotedOngoingEntry() + val otherEntry = buildNotificationEntry(tag = "other") + + renderNotificationListInteractor.setRenderedList( + listOf(callEntry, ronEntry, otherEntry) + ) + + val orderedChipNotificationKeys by + collectLastValue(underTest.orderedChipNotificationKeys) + + // THEN the order of the notification keys should be the call then the RON + assertThat(orderedChipNotificationKeys) + .containsExactly("0|test_pkg|0|call|0", "0|test_pkg|0|ron|0") + } + + @Test + fun topPromotedNotificationContent_skipsNonPromotedCalls() = + kosmos.runTest { + // GIVEN a non-promoted call and a promoted ongoing notification + val callEntry = buildOngoingCallEntry(promoted = false) + val ronEntry = buildPromotedOngoingEntry() + val otherEntry = buildNotificationEntry(tag = "other") + + renderNotificationListInteractor.setRenderedList( + listOf(callEntry, ronEntry, otherEntry) + ) + + val topPromotedNotificationContent by + collectLastValue(underTest.topPromotedNotificationContent) + + // THEN the ron is first because the call has no content + assertThat(topPromotedNotificationContent?.identity?.key) + .isEqualTo("0|test_pkg|0|ron|0") + } + + @Test + fun topPromotedNotificationContent_includesPromotedCalls() = + kosmos.runTest { + // GIVEN a promoted call and a promoted ongoing notification + val callEntry = buildOngoingCallEntry(promoted = true) + val ronEntry = buildPromotedOngoingEntry() + val otherEntry = buildNotificationEntry(tag = "other") + + renderNotificationListInteractor.setRenderedList( + listOf(callEntry, ronEntry, otherEntry) + ) + + val topPromotedNotificationContent by + collectLastValue(underTest.topPromotedNotificationContent) + + // THEN the call is the top notification + assertThat(topPromotedNotificationContent?.identity?.key) + .isEqualTo("0|test_pkg|0|call|0") + } + + @Test + fun topPromotedNotificationContent_nullWithNoPromotedNotifications() = + kosmos.runTest { + // GIVEN a a non-promoted call and no promoted ongoing entry + val callEntry = buildOngoingCallEntry(promoted = false) + val otherEntry = buildNotificationEntry(tag = "other") + + renderNotificationListInteractor.setRenderedList(listOf(callEntry, otherEntry)) + + val topPromotedNotificationContent by + collectLastValue(underTest.topPromotedNotificationContent) + + // THEN there is no top promoted notification + assertThat(topPromotedNotificationContent).isNull() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java index 7d406b4b397c..9f35d631bd45 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java @@ -67,6 +67,7 @@ import com.android.systemui.media.controls.util.MediaFeatureFlag; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips; import com.android.systemui.statusbar.notification.ConversationNotificationProcessor; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi; @@ -248,14 +249,13 @@ public class NotificationContentInflaterTest extends SysuiTestCase { true /* isNewView */, (v, p, r) -> true, new InflationCallback() { @Override - public void handleInflationException(NotificationEntry entry, - Exception e) { + public void handleInflationException(Exception e) { countDownLatch.countDown(); throw new RuntimeException("No Exception expected"); } @Override - public void onAsyncInflationFinished(NotificationEntry entry) { + public void onAsyncInflationFinished() { countDownLatch.countDown(); } }, mRow.getPrivateLayout(), null, null, new HashMap<>(), @@ -539,8 +539,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { inflater.setInflateSynchronously(true); InflationCallback callback = new InflationCallback() { @Override - public void handleInflationException(NotificationEntry entry, - Exception e) { + public void handleInflationException(Exception e) { if (!expectingException) { exceptionHolder.setException(e); } @@ -548,7 +547,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase { } @Override - public void onAsyncInflationFinished(NotificationEntry entry) { + public void onAsyncInflationFinished() { if (expectingException) { exceptionHolder.setException(new RuntimeException( "Inflation finished even though there should be an error")); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt index 4c1f4f17e00c..1b8d64d5483c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt @@ -80,9 +80,6 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.testKosmos import com.android.systemui.util.kotlin.JavaAdapter import com.android.systemui.wmshell.BubblesManager -import java.util.Optional -import kotlin.test.assertNotNull -import kotlin.test.fail import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals @@ -110,6 +107,9 @@ import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import platform.test.runner.parameterized.ParameterizedAndroidJunit4 import platform.test.runner.parameterized.Parameters +import java.util.Optional +import kotlin.test.assertNotNull +import kotlin.test.fail /** Tests for [NotificationGutsManager]. */ @SmallTest @@ -509,7 +509,6 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase( .setImportance(NotificationManager.IMPORTANCE_HIGH) .build() - whenever(row.isNonblockable).thenReturn(false) whenever(highPriorityProvider.isHighPriority(entry)).thenReturn(true) val statusBarNotification = entry.sbn gutsManager.initializeNotificationInfo(row, notificationInfoView) @@ -546,7 +545,6 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase( NotificationEntryHelper.modifyRanking(row.entry) .setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE) .build() - whenever(row.isNonblockable).thenReturn(false) val statusBarNotification = row.entry.sbn val entry = row.entry @@ -586,7 +584,6 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase( NotificationEntryHelper.modifyRanking(row.entry) .setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE) .build() - whenever(row.isNonblockable).thenReturn(false) val statusBarNotification = row.entry.sbn val entry = row.entry @@ -641,7 +638,7 @@ class NotificationGutsManagerTest(flags: FlagsParameterization) : SysuiTestCase( ): NotificationMenuRowPlugin.MenuItem { val menuRow: NotificationMenuRowPlugin = NotificationMenuRow(mContext, peopleNotificationIdentifier) - menuRow.createMenu(row, row.entry.sbn) + menuRow.createMenu(row) val menuItem = menuRow.getLongpressMenuItem(mContext) assertNotNull(menuItem) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java index 027e899e20df..9fdfca14a5b2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationMenuRowTest.java @@ -72,7 +72,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest { public void testAttachDetach() { NotificationMenuRowPlugin row = new NotificationMenuRow(mContext, mPeopleNotificationIdentifier); - row.createMenu(mRow, null); + row.createMenu(mRow); ViewUtils.attachView(row.getMenuView()); TestableLooper.get(this).processAllMessages(); ViewUtils.detachView(row.getMenuView()); @@ -83,9 +83,9 @@ public class NotificationMenuRowTest extends LeakCheckedTest { public void testRecreateMenu() { NotificationMenuRowPlugin row = new NotificationMenuRow(mContext, mPeopleNotificationIdentifier); - row.createMenu(mRow, null); + row.createMenu(mRow); assertTrue(row.getMenuView() != null); - row.createMenu(mRow, null); + row.createMenu(mRow); assertTrue(row.getMenuView() != null); } @@ -103,7 +103,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest { Settings.Global.putInt(mContext.getContentResolver(), SHOW_NEW_NOTIF_DISMISS, 0); NotificationMenuRow row = new NotificationMenuRow(mContext, mPeopleNotificationIdentifier); - row.createMenu(mRow, null); + row.createMenu(mRow); ViewGroup container = (ViewGroup) row.getMenuView(); // noti blocking @@ -116,7 +116,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest { Settings.Global.putInt(mContext.getContentResolver(), SHOW_NEW_NOTIF_DISMISS, 0); NotificationMenuRow row = new NotificationMenuRow(mContext, mPeopleNotificationIdentifier); - row.createMenu(mRow, null); + row.createMenu(mRow); ViewGroup container = (ViewGroup) row.getMenuView(); // just for noti blocking @@ -129,7 +129,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest { Settings.Global.putInt(mContext.getContentResolver(), SHOW_NEW_NOTIF_DISMISS, 0); NotificationMenuRow row = new NotificationMenuRow(mContext, mPeopleNotificationIdentifier); - row.createMenu(mRow, null); + row.createMenu(mRow); ViewGroup container = (ViewGroup) row.getMenuView(); // one for snooze and one for noti blocking @@ -142,7 +142,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest { Settings.Global.putInt(mContext.getContentResolver(), SHOW_NEW_NOTIF_DISMISS, 1); NotificationMenuRow row = new NotificationMenuRow(mContext, mPeopleNotificationIdentifier); - row.createMenu(mRow, null); + row.createMenu(mRow); ViewGroup container = (ViewGroup) row.getMenuView(); // Clear menu @@ -417,7 +417,7 @@ public class NotificationMenuRowTest extends LeakCheckedTest { public void testOnTouchMove() { NotificationMenuRow row = Mockito.spy( new NotificationMenuRow(mContext, mPeopleNotificationIdentifier)); - row.createMenu(mRow, null); + row.createMenu(mRow); doReturn(50f).when(row).getDismissThreshold(); doReturn(true).when(row).canBeDismissed(); doReturn(mView).when(row).getMenuView(); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt index 82eca3735a71..ce3aee1d88d2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt @@ -41,6 +41,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager.REDACTIO import com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.notification.ConversationNotificationProcessor +import com.android.systemui.statusbar.notification.collection.EntryAdapter import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi @@ -223,12 +224,12 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { remoteViewClickHandler = { _, _, _ -> true }, callback = object : InflationCallback { - override fun handleInflationException(entry: NotificationEntry, e: Exception) { + override fun handleInflationException(e: Exception) { countDownLatch.countDown() throw RuntimeException("No Exception expected") } - override fun onAsyncInflationFinished(entry: NotificationEntry) { + override fun onAsyncInflationFinished() { countDownLatch.countDown() } }, @@ -675,14 +676,14 @@ class NotificationRowContentBinderImplTest : SysuiTestCase() { inflater.setInflateSynchronously(true) val callback: InflationCallback = object : InflationCallback { - override fun handleInflationException(entry: NotificationEntry, e: Exception) { + override fun handleInflationException(e: Exception) { if (!expectingException) { exceptionHolder.exception = e } countDownLatch.countDown() } - override fun onAsyncInflationFinished(entry: NotificationEntry) { + override fun onAsyncInflationFinished() { if (expectingException) { exceptionHolder.exception = RuntimeException( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index c39b252cd795..f2131da8f0bb 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -615,7 +615,7 @@ public class NotificationTestHelper { LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE); inflater.setFactory2(new RowInflaterTask.RowAsyncLayoutInflater(entry, mSystemClock, - mRowInflaterTaskLogger)); + mRowInflaterTaskLogger, UserHandle.of(entry.getSbn().getNormalizedUserId()))); mRow = (ExpandableNotificationRow) inflater.inflate( R.layout.status_bar_notification_row, null /* root */, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt index d570f18e35d8..6381b4e0fef7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt @@ -57,11 +57,12 @@ class NotificationShelfViewModelTest : SysuiTestCase() { statusBarStateController = mock() whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true) } - private val underTest = kosmos.notificationShelfViewModel private val deviceEntryFaceAuthRepository = kosmos.fakeDeviceEntryFaceAuthRepository private val keyguardRepository = kosmos.fakeKeyguardRepository - private val keyguardTransitionController = kosmos.lockscreenShadeTransitionController private val powerRepository = kosmos.fakePowerRepository + private val keyguardTransitionController by lazy { kosmos.lockscreenShadeTransitionController } + + private val underTest by lazy { kosmos.notificationShelfViewModel } @Test fun canModifyColorOfNotifications_whenKeyguardNotShowing() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt index e5cb0fbc9e4b..885e71e7a7fe 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImplTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.testKosmos import com.google.android.msdl.data.model.MSDLToken import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -49,7 +50,7 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { private val sectionsManager = mock<NotificationSectionsManager>() private val msdlPlayer = kosmos.fakeMSDLPlayer private var canRowBeDismissed = true - private var magneticAnimationsCancelled = false + private var magneticAnimationsCancelled = MutableList(childrenNumber) { false } private val underTest = kosmos.magneticNotificationRowManagerImpl @@ -64,8 +65,10 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { NotificationTestHelper(mContext, mDependency, kosmos.testableLooper, featureFlags) children = notificationTestHelper.createGroup(childrenNumber).childrenContainer swipedRow = children.attachedChildren[childrenNumber / 2] - configureMagneticRowListener(swipedRow) - magneticAnimationsCancelled = false + children.attachedChildren.forEachIndexed { index, row -> + row.magneticRowListener = row.magneticRowListener.asTestableListener(index) + } + magneticAnimationsCancelled.replaceAll { false } } @Test @@ -259,14 +262,14 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { underTest.onMagneticInteractionEnd(swipedRow, velocity = null) // THEN magnetic animations are cancelled - assertThat(magneticAnimationsCancelled).isTrue() + assertThat(magneticAnimationsCancelled[childrenNumber / 2]).isTrue() } @Test fun onMagneticInteractionEnd_forMagneticNeighbor_cancelsMagneticAnimations() = kosmos.testScope.runTest { - val neighborRow = children.attachedChildren[childrenNumber / 2 - 1] - configureMagneticRowListener(neighborRow) + val neighborIndex = childrenNumber / 2 - 1 + val neighborRow = children.attachedChildren[neighborIndex] // GIVEN that targets are set setTargets() @@ -275,9 +278,15 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { underTest.onMagneticInteractionEnd(neighborRow, null) // THEN magnetic animations are cancelled - assertThat(magneticAnimationsCancelled).isTrue() + assertThat(magneticAnimationsCancelled[neighborIndex]).isTrue() } + @After + fun tearDown() { + // We reset the manager so that all MagneticRowListener can cancel all animations + underTest.reset() + } + private fun setDetachedState() { val threshold = 100f underTest.setSwipeThresholdPx(threshold) @@ -302,27 +311,33 @@ class MagneticNotificationRowManagerImplTest : SysuiTestCase() { originalTranslation * MagneticNotificationRowManagerImpl.MAGNETIC_REDUCTION - private fun configureMagneticRowListener(row: ExpandableNotificationRow) { - val listener = - object : MagneticRowListener { - override fun setMagneticTranslation(translation: Float) { - row.translation = translation - } + private fun MagneticRowListener.asTestableListener(rowIndex: Int): MagneticRowListener { + val delegate = this + return object : MagneticRowListener { + override fun setMagneticTranslation(translation: Float) { + delegate.setMagneticTranslation(translation) + } - override fun triggerMagneticForce( - endTranslation: Float, - springForce: SpringForce, - startVelocity: Float, - ) {} + override fun triggerMagneticForce( + endTranslation: Float, + springForce: SpringForce, + startVelocity: Float, + ) { + delegate.triggerMagneticForce(endTranslation, springForce, startVelocity) + } - override fun cancelMagneticAnimations() { - magneticAnimationsCancelled = true - } + override fun cancelMagneticAnimations() { + magneticAnimationsCancelled[rowIndex] = true + delegate.cancelMagneticAnimations() + } - override fun cancelTranslationAnimations() {} + override fun cancelTranslationAnimations() { + delegate.cancelTranslationAnimations() + } - override fun canRowBeDismissed(): Boolean = canRowBeDismissed + override fun canRowBeDismissed(): Boolean { + return canRowBeDismissed } - row.magneticRowListener = listener + } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt index 3a77d822eb7e..52f903e20ab8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt @@ -31,7 +31,7 @@ class MediaContainerViewTest : SysuiTestCase() { fun testUpdateClipping_updatesClipHeight() { assertTrue(mediaContainerView.clipHeight == 0) - mediaContainerView.actualHeight = 10 + mediaContainerView.setFinalActualHeight(10) mediaContainerView.updateClipping() assertTrue(mediaContainerView.clipHeight == 10) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt index 256da253588c..9c5d65ec12ec 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt @@ -1,5 +1,6 @@ package com.android.systemui.statusbar.notification.stack +import android.os.UserHandle import android.platform.test.annotations.EnableFlags import android.service.notification.StatusBarNotification import android.testing.TestableLooper.RunWithLooper @@ -21,6 +22,7 @@ import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.android.systemui.statusbar.notification.shared.NotificationMinimalism import com.android.systemui.statusbar.notification.shelf.NotificationShelfIconContainer import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.StackScrollAlgorithmState @@ -978,7 +980,10 @@ open class NotificationShelfTest : SysuiTestCase() { ) { val sbnMock: StatusBarNotification = mock() val mockEntry = mock<NotificationEntry>().apply { whenever(this.sbn).thenReturn(sbnMock) } - val row = ExpandableNotificationRow(mContext, null, mockEntry) + val row = when (NotificationBundleUi.isEnabled) { + true -> ExpandableNotificationRow(mContext, null, UserHandle.CURRENT) + false -> ExpandableNotificationRow(mContext, null, mockEntry) + } whenever(ambientState.lastVisibleBackgroundChild).thenReturn(row) whenever(ambientState.isExpansionChanging).thenReturn(true) whenever(ambientState.expansionFraction).thenReturn(expansionFraction) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt index 51de9d5d7514..87cd728d106f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelperTest.kt @@ -14,6 +14,7 @@ import junit.framework.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.whenever /** Tests for {@link NotificationTargetsHelper}. */ @SmallTest @@ -21,7 +22,7 @@ import org.junit.runner.RunWith @RunWithLooper class NotificationTargetsHelperTest : SysuiTestCase() { private val featureFlags = FakeFeatureFlagsClassic() - lateinit var notificationTestHelper: NotificationTestHelper + private lateinit var notificationTestHelper: NotificationTestHelper private val sectionsManager: NotificationSectionsManager = mock() private val stackScrollLayout: NotificationStackScrollLayout = mock() @@ -107,7 +108,12 @@ class NotificationTargetsHelperTest : SysuiTestCase() { // THEN all the views that surround it become targets with the swiped view at the middle val actual = notificationTargetsHelper() - .findMagneticTargets(viewSwiped = swiped, stackScrollLayout = stackScrollLayout, 5) + .findMagneticTargets( + viewSwiped = swiped, + stackScrollLayout = stackScrollLayout, + sectionsManager, + totalMagneticTargets = 5, + ) assertMagneticTargetsForChildren(actual, children.attachedChildren) } @@ -123,7 +129,12 @@ class NotificationTargetsHelperTest : SysuiTestCase() { // to the left val actual = notificationTargetsHelper() - .findMagneticTargets(viewSwiped = swiped, stackScrollLayout = stackScrollLayout, 5) + .findMagneticTargets( + viewSwiped = swiped, + stackScrollLayout = stackScrollLayout, + sectionsManager, + totalMagneticTargets = 5, + ) val expectedRows = listOf(null, null, swiped, children.attachedChildren[1], children.attachedChildren[2]) assertMagneticTargetsForChildren(actual, expectedRows) @@ -141,7 +152,12 @@ class NotificationTargetsHelperTest : SysuiTestCase() { // to the right val actual = notificationTargetsHelper() - .findMagneticTargets(viewSwiped = swiped, stackScrollLayout = stackScrollLayout, 5) + .findMagneticTargets( + viewSwiped = swiped, + stackScrollLayout = stackScrollLayout, + sectionsManager, + totalMagneticTargets = 5, + ) val expectedRows = listOf( children.attachedChildren[childrenNumber - 3], @@ -153,6 +169,54 @@ class NotificationTargetsHelperTest : SysuiTestCase() { assertMagneticTargetsForChildren(actual, expectedRows) } + @Test + fun findMagneticTargets_doesNotCrossSectionAtTop() { + val childrenNumber = 5 + val children = notificationTestHelper.createGroup(childrenNumber).childrenContainer + + // WHEN the second child is swiped and the first one begins a new section + val swiped = children.attachedChildren[1] + whenever(sectionsManager.beginsSection(swiped, children.attachedChildren[0])).then { true } + + // THEN the neighboring views become targets, with the swiped view at the middle and nulls + // to the left since the top view relative to swiped begins a new section + val actual = + notificationTargetsHelper() + .findMagneticTargets( + viewSwiped = swiped, + stackScrollLayout = stackScrollLayout, + sectionsManager, + totalMagneticTargets = 5, + ) + val expectedRows = + listOf(null, null, swiped, children.attachedChildren[2], children.attachedChildren[3]) + assertMagneticTargetsForChildren(actual, expectedRows) + } + + @Test + fun findMagneticTargets_doesNotCrossSectionAtBottom() { + val childrenNumber = 5 + val children = notificationTestHelper.createGroup(childrenNumber).childrenContainer + + // WHEN the fourth child is swiped and the last one begins a new section + val swiped = children.attachedChildren[3] + whenever(sectionsManager.beginsSection(children.attachedChildren[4], swiped)).then { true } + + // THEN the neighboring views become targets, with the swiped view at the middle and nulls + // to the right since the bottom view relative to swiped begins a new section + val actual = + notificationTargetsHelper() + .findMagneticTargets( + viewSwiped = swiped, + stackScrollLayout = stackScrollLayout, + sectionsManager, + totalMagneticTargets = 5, + ) + val expectedRows = + listOf(children.attachedChildren[1], children.attachedChildren[2], swiped, null, null) + assertMagneticTargetsForChildren(actual, expectedRows) + } + private fun assertMagneticTargetsForChildren( targets: List<MagneticRowListener?>, children: List<ExpandableNotificationRow?>, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt index 01ba4df3a314..7603eecd27ff 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt @@ -146,6 +146,20 @@ class StackScrollAlgorithmTest(flags: FlagsParameterization) : SysuiTestCase() { } @Test + @EnableSceneContainer + fun resetViewStates_defaultHun_hasShadow() { + val headsUpTop = 200f + ambientState.headsUpTop = headsUpTop + + whenever(notificationRow.isPinned).thenReturn(true) + whenever(notificationRow.isHeadsUp).thenReturn(true) + + stackScrollAlgorithm.resetViewStates(ambientState, 0) + + assertThat(notificationRow.viewState.zTranslation).isGreaterThan(baseZ) + } + + @Test @DisableSceneContainer fun resetViewStates_defaultHunWhenShadeIsOpening_yTranslationIsInset() { whenever(notificationRow.isPinned).thenReturn(true) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt index e4dd29ad83b0..67415de86d9b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt @@ -81,7 +81,7 @@ class StackStateAnimatorTest : SysuiTestCase() { stackStateAnimator.startAnimationForEvents(arrayListOf(event), 0) - verify(view).setActualHeight(VIEW_HEIGHT, false) + verify(view).setFinalActualHeight(VIEW_HEIGHT) verify(view, description("should animate from the top")).translationY = expectedStartY verify(view) .performAddAnimation( @@ -104,7 +104,7 @@ class StackStateAnimatorTest : SysuiTestCase() { stackStateAnimator.startAnimationForEvents(arrayListOf(event), 0) - verify(view).setActualHeight(VIEW_HEIGHT, false) + verify(view).setFinalActualHeight(VIEW_HEIGHT) verify(view, description("should animate from the bottom")).translationY = expectedStartY verify(view) .performAddAnimation( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt index e493420b64a1..ef415c918f91 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt @@ -16,21 +16,28 @@ package com.android.systemui.statusbar.notification.stack +import android.animation.ValueAnimator +import android.view.View +import androidx.test.annotation.UiThreadTest import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.log.assertDoesNotLogWtf import com.android.systemui.log.assertLogsWtf -import kotlin.math.log2 -import kotlin.math.sqrt +import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator +import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.Companion.TAG_ANIMATOR_TRANSLATION_Y +import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.Companion.Y_TRANSLATION import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith +import kotlin.math.log2 +import kotlin.math.sqrt @RunWith(AndroidJUnit4::class) @SmallTest +@UiThreadTest class ViewStateTest : SysuiTestCase() { - private val viewState = ViewState() + private val viewState = ViewState(true /* usePhysicsForMovement */) @Suppress("DIVISION_BY_ZERO") @Test @@ -64,4 +71,37 @@ class ViewStateTest : SysuiTestCase() { assertLogsWtf { viewState.scaleY = Float.POSITIVE_INFINITY * 0 } Assert.assertEquals(viewState.scaleY, 0.25f) } + + @Test + fun testUsingPhysics() { + val animatedView = View(context) + viewState.setUsePhysicsForMovement(true) + viewState.applyToView(animatedView) + viewState.yTranslation = 100f + val animationFilter = AnimationFilter().animateY() + val animationProperties = object : AnimationProperties() { + override fun getAnimationFilter(): AnimationFilter { + return animationFilter + } + } + viewState.animateTo(animatedView, animationProperties) + Assert.assertTrue(PhysicsPropertyAnimator.isAnimating(animatedView, Y_TRANSLATION)) + } + + @Test + fun testNotUsingPhysics() { + val animatedView = View(context) + viewState.setUsePhysicsForMovement(false) + viewState.applyToView(animatedView) + viewState.yTranslation = 100f + val animationFilter = AnimationFilter().animateY() + val animationProperties = object : AnimationProperties() { + override fun getAnimationFilter(): AnimationFilter { + return animationFilter + } + } + viewState.animateTo(animatedView, animationProperties) + val tag = animatedView.getTag(TAG_ANIMATOR_TRANSLATION_Y) + Assert.assertTrue(tag is ValueAnimator) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java index 8ec17dadcfe7..345ddae42798 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java @@ -46,9 +46,11 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntry.NotifEntryAdapter; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationContentView; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; @@ -133,9 +135,11 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class); final NotificationContentView privateLayout = mock(NotificationContentView.class); final NotificationEntry enrEntry = mock(NotificationEntry.class); + final NotifEntryAdapter enrEntryAdapter = mock(NotifEntryAdapter.class); when(enr.getPrivateLayout()).thenReturn(privateLayout); when(enr.getEntry()).thenReturn(enrEntry); + when(enr.getEntryAdapter()).thenReturn(enrEntryAdapter); when(enr.isChildInGroup()).thenReturn(true); when(enr.areChildrenExpanded()).thenReturn(false); @@ -144,7 +148,11 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { enr, mock(View.class), false, onExpandedVisibleRunner); // THEN - verify(mGroupExpansionManager).toggleGroupExpansion(enrEntry); + if (NotificationBundleUi.isEnabled()) { + verify(mGroupExpansionManager).toggleGroupExpansion(enrEntryAdapter); + } else { + verify(mGroupExpansionManager).toggleGroupExpansion(enrEntry); + } verify(enr).setUserExpanded(true); verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner); } @@ -169,7 +177,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { enr, mock(View.class), false, onExpandedVisibleRunner); // THEN - verify(mGroupExpansionManager, never()).toggleGroupExpansion(any()); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class)); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class)); verify(enr).setUserExpanded(true); verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner); } @@ -193,7 +202,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { enr, mock(View.class), false, onExpandedVisibleRunner); // THEN - verify(mGroupExpansionManager, never()).toggleGroupExpansion(any()); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class)); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class)); verify(enr).setUserExpanded(true); verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner); } @@ -207,9 +217,11 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class); final NotificationContentView privateLayout = mock(NotificationContentView.class); final NotificationEntry enrEntry = mock(NotificationEntry.class); + final NotifEntryAdapter enrEntryAdapter = mock(NotifEntryAdapter.class); when(enr.getPrivateLayout()).thenReturn(privateLayout); when(enr.getEntry()).thenReturn(enrEntry); + when(enr.getEntryAdapter()).thenReturn(enrEntryAdapter); when(enr.isChildInGroup()).thenReturn(true); when(enr.areChildrenExpanded()).thenReturn(false); @@ -218,7 +230,11 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { enr, mock(View.class), false, onExpandedVisibleRunner); // THEN - verify(mGroupExpansionManager).toggleGroupExpansion(enrEntry); + if (NotificationBundleUi.isEnabled()) { + verify(mGroupExpansionManager).toggleGroupExpansion(enrEntryAdapter); + } else { + verify(mGroupExpansionManager).toggleGroupExpansion(enrEntry); + } verify(enr, never()).setUserExpanded(anyBoolean()); verify(privateLayout, never()).setOnExpandedVisibleListener(any()); } @@ -244,6 +260,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { // THEN verify(mGroupExpansionManager, never()).toggleGroupExpansion(enrEntry); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class)); verify(enr, never()).setUserExpanded(anyBoolean()); verify(privateLayout, never()).setOnExpandedVisibleListener(any()); } @@ -272,7 +289,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { verify(enr).toggleExpansionState(); verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner); verify(enr, never()).setUserExpanded(anyBoolean()); - verify(mGroupExpansionManager, never()).toggleGroupExpansion(any()); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class)); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class)); } @Test @@ -299,7 +317,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { verify(enr, never()).toggleExpansionState(); verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner); verify(enr, never()).setUserExpanded(anyBoolean()); - verify(mGroupExpansionManager, never()).toggleGroupExpansion(any()); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class)); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class)); } @Test @@ -326,7 +345,8 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { verify(enr).toggleExpansionState(); verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner); verify(enr, never()).setUserExpanded(anyBoolean()); - verify(mGroupExpansionManager, never()).toggleGroupExpansion(any()); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class)); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class)); } @Test @@ -353,6 +373,7 @@ public class StatusBarRemoteInputCallbackTest extends SysuiTestCase { verify(enr, never()).toggleExpansionState(); verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner); verify(enr, never()).setUserExpanded(anyBoolean()); - verify(mGroupExpansionManager, never()).toggleGroupExpansion(any()); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class)); + verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class)); } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt index c48287c32120..bab349aa7a74 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractorTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.phone.ongoingcall.domain.interactor import android.app.PendingIntent -import android.platform.test.annotations.EnableFlags import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -31,9 +30,8 @@ import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository import com.android.systemui.statusbar.gesture.swipeStatusBarAwayGestureHandler -import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel -import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.addOngoingCallState import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.removeOngoingCallState @@ -51,10 +49,9 @@ import org.mockito.kotlin.verify @SmallTest @RunWith(AndroidJUnit4::class) -@EnableFlags(StatusBarChipsModernization.FLAG_NAME) +@EnableChipsModernization class OngoingCallInteractorTest : SysuiTestCase() { private val kosmos = Kosmos().useUnconfinedTestDispatcher() - private val repository = kosmos.activeNotificationListRepository private val underTest = kosmos.ongoingCallInteractor @Before @@ -69,18 +66,19 @@ class OngoingCallInteractorTest : SysuiTestCase() { } @Test - fun ongoingCallNotification_setsAllFields() = + fun ongoingCallNotification_setsAllFields_withAppHidden() = kosmos.runTest { val latest by collectLastValue(underTest.ongoingCallState) // Set up notification with icon view and intent + val key = "promotedCall" + val startTimeMs = 1000L val testIconView: StatusBarIconView = mock() val testIntent: PendingIntent = mock() - val testPromotedContent = - PromotedNotificationContentModel.Builder("promotedCall").build() + val testPromotedContent = PromotedNotificationContentModel.Builder(key).build() addOngoingCallState( - key = "promotedCall", - startTimeMs = 1000L, + key = key, + startTimeMs = startTimeMs, statusBarChipIconView = testIconView, contentIntent = testIntent, promotedContent = testPromotedContent, @@ -89,8 +87,41 @@ class OngoingCallInteractorTest : SysuiTestCase() { // Verify model is InCall and has the correct icon, intent, and promoted content. assertThat(latest).isInstanceOf(OngoingCallModel.InCall::class.java) val model = latest as OngoingCallModel.InCall + assertThat(model.startTimeMs).isEqualTo(startTimeMs) assertThat(model.notificationIconView).isSameInstanceAs(testIconView) assertThat(model.intent).isSameInstanceAs(testIntent) + assertThat(model.notificationKey).isEqualTo(key) + assertThat(model.promotedContent).isSameInstanceAs(testPromotedContent) + } + + @Test + fun ongoingCallNotification_setsAllFields_withAppVisible() = + kosmos.runTest { + kosmos.activityManagerRepository.fake.startingIsAppVisibleValue = true + val latest by collectLastValue(underTest.ongoingCallState) + + // Set up notification with icon view and intent + val key = "promotedCall" + val startTimeMs = 1000L + val testIconView: StatusBarIconView = mock() + val testIntent: PendingIntent = mock() + val testPromotedContent = PromotedNotificationContentModel.Builder(key).build() + addOngoingCallState( + key = key, + startTimeMs = startTimeMs, + statusBarChipIconView = testIconView, + contentIntent = testIntent, + promotedContent = testPromotedContent, + ) + + // Verify model is InCallWithVisibleApp and has the correct icon, intent, and promoted + // content. + assertThat(latest).isInstanceOf(OngoingCallModel.InCallWithVisibleApp::class.java) + val model = latest as OngoingCallModel.InCallWithVisibleApp + assertThat(model.startTimeMs).isEqualTo(startTimeMs) + assertThat(model.notificationIconView).isSameInstanceAs(testIconView) + assertThat(model.intent).isSameInstanceAs(testIntent) + assertThat(model.notificationKey).isEqualTo(key) assertThat(model.promotedContent).isSameInstanceAs(testPromotedContent) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt index 4009144757f7..8c70da718c08 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt @@ -719,7 +719,6 @@ class MobileIconInteractorTest : SysuiTestCase() { job.cancel() } - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @Test fun satBasedIcon_isUsedWhenNonTerrestrial() = testScope.runTest { @@ -733,7 +732,6 @@ class MobileIconInteractorTest : SysuiTestCase() { assertThat(latest).isInstanceOf(SignalIconModel.Satellite::class.java) } - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test // See b/346904529 for more context @@ -756,10 +754,7 @@ class MobileIconInteractorTest : SysuiTestCase() { assertThat(latest!!.level).isEqualTo(4) } - @EnableFlags( - com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG, - com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN, - ) + @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test // See b/346904529 for more context fun satBasedIcon_doesNotInflateSignalStrength_flagOn() = @@ -781,7 +776,6 @@ class MobileIconInteractorTest : SysuiTestCase() { assertThat(latest!!.level).isEqualTo(4) } - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test fun satBasedIcon_usesPrimaryLevel_flagOff() = @@ -799,10 +793,7 @@ class MobileIconInteractorTest : SysuiTestCase() { assertThat(latest!!.level).isEqualTo(4) } - @EnableFlags( - com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG, - com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN, - ) + @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test fun satBasedIcon_usesSatelliteLevel_flagOn() = testScope.runTest { @@ -823,7 +814,6 @@ class MobileIconInteractorTest : SysuiTestCase() { * Context (b/377518113), this test will not be needed after FLAG_CARRIER_ROAMING_NB_IOT_NTN is * rolled out. The new API should report 0 automatically if not in service. */ - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test fun satBasedIcon_reportsLevelZeroWhenOutOfService() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt index 61ed04c6b59d..8ea888e47ffc 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt @@ -856,7 +856,6 @@ class MobileIconViewModelTest : SysuiTestCase() { .isEqualTo(Icon.Resource(R.drawable.mobile_network_type_background, null)) } - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @Test fun nonTerrestrial_defaultProperties() = testScope.runTest { @@ -877,7 +876,6 @@ class MobileIconViewModelTest : SysuiTestCase() { assertThat(activityContainerVisible).isFalse() } - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @Test fun nonTerrestrial_ignoresDefaultProperties() = testScope.runTest { @@ -905,7 +903,6 @@ class MobileIconViewModelTest : SysuiTestCase() { assertThat(activityContainerVisible).isFalse() } - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test fun nonTerrestrial_usesSatelliteIcon_flagOff() = @@ -940,10 +937,7 @@ class MobileIconViewModelTest : SysuiTestCase() { assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2) } - @EnableFlags( - com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG, - com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN, - ) + @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test fun nonTerrestrial_usesSatelliteIcon_flagOn() = testScope.runTest { @@ -972,7 +966,6 @@ class MobileIconViewModelTest : SysuiTestCase() { assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2) } - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test fun satelliteIcon_ignoresInflateSignalStrength_flagOff() = @@ -1010,10 +1003,7 @@ class MobileIconViewModelTest : SysuiTestCase() { assertThat(latest!!.icon.res).isEqualTo(R.drawable.ic_satellite_connected_2) } - @EnableFlags( - com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG, - com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN, - ) + @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN) @Test fun satelliteIcon_ignoresInflateSignalStrength_flagOn() = testScope.runTest { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt index 183cd8f1ae8b..f91e3a612862 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt @@ -57,13 +57,15 @@ class FakeHomeStatusBarViewModel( override val ongoingActivityChipsLegacy = MutableStateFlow(MultipleOngoingActivityChipsModelLegacy()) - override val statusBarPopupChips = MutableStateFlow(emptyList<PopupChipModel.Shown>()) + override val popupChips = emptyList<PopupChipModel.Shown>() override val mediaProjectionStopDialogDueToCallEndedState = MutableStateFlow(MediaProjectionStopDialogModel.Hidden) override val isHomeStatusBarAllowedByScene = MutableStateFlow(false) + override val canShowOngoingActivityChips: Flow<Boolean> = MutableStateFlow(false) + override val batteryViewModelFactory: BatteryViewModel.Factory = object : BatteryViewModel.Factory { override fun create(): BatteryViewModel = mock(BatteryViewModel::class.java) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt index cd8ca23e0964..8a796fc33608 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt @@ -86,6 +86,7 @@ import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataS import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository import com.android.systemui.statusbar.phone.SysuiDarkIconDispatcher import com.android.systemui.statusbar.phone.data.repository.fakeDarkIconRepository +import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarIconBlockList import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarInteractorShowOperatorName @@ -677,6 +678,60 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { } @Test + fun canShowOngoingActivityChips_statusBarHidden_noSecureCamera_noHun_false() = + kosmos.runTest { + val latest by collectLastValue(underTest.canShowOngoingActivityChips) + + // home status bar not allowed + kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen) + kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, taskInfo = null) + + assertThat(latest).isFalse() + } + + @Test + fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_noHun_true() = + kosmos.runTest { + val latest by collectLastValue(underTest.canShowOngoingActivityChips) + + transitionKeyguardToGone() + + assertThat(latest).isTrue() + } + + @Test + fun canShowOngoingActivityChips_statusBarNotHidden_secureCamera_noHun_false() = + kosmos.runTest { + val latest by collectLastValue(underTest.canShowOngoingActivityChips) + + fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.OCCLUDED, + testScope = testScope, + ) + kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) + + assertThat(latest).isFalse() + } + + @Test + fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hun_false() = + kosmos.runTest { + val latest by collectLastValue(underTest.canShowOngoingActivityChips) + + transitionKeyguardToGone() + + headsUpNotificationRepository.setNotifications( + UnconfinedFakeHeadsUpRowRepository( + key = "key", + pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser), + ) + ) + + assertThat(latest).isFalse() + } + + @Test fun isClockVisible_allowedByDisableFlags_visible() = kosmos.runTest { val latest by collectLastValue(underTest.isClockVisible) @@ -835,7 +890,7 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() { } @Test - @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME) + @EnableChipsModernization fun isNotificationIconContainerVisible_anyChipShowing_ChipsModernizationOn() = kosmos.runTest { val latest by collectLastValue(underTest.isNotificationIconContainerVisible) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java index 8593f6a08b5a..605e4a47275b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/RotationLockControllerImplTest.java @@ -37,15 +37,19 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Optional; + @RunWith(AndroidJUnit4.class) @TestableLooper.RunWithLooper @SmallTest public class RotationLockControllerImplTest extends SysuiTestCase { - private static final String[] DEFAULT_SETTINGS = new String[] {"0:0", "1:2"}; + private static final String[] DEFAULT_SETTINGS = new String[]{"0:0", "1:2"}; - @Mock RotationPolicyWrapper mRotationPolicyWrapper; - @Mock DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController; + @Mock + RotationPolicyWrapper mRotationPolicyWrapper; + @Mock + DeviceStateRotationLockSettingController mDeviceStateRotationLockSettingController; private ArgumentCaptor<RotationPolicy.RotationPolicyListener> mRotationPolicyListenerCaptor; @@ -93,7 +97,7 @@ public class RotationLockControllerImplTest extends SysuiTestCase { private void createRotationLockController(String[] deviceStateRotationLockDefaults) { new RotationLockControllerImpl( mRotationPolicyWrapper, - mDeviceStateRotationLockSettingController, + Optional.of(mDeviceStateRotationLockSettingController), deviceStateRotationLockDefaults); } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt index 799e957656dc..bab5a2d6793d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.policy import android.app.IActivityManager +import android.app.role.RoleManager import android.content.pm.PackageManager import android.media.projection.MediaProjectionManager import android.os.Handler @@ -48,6 +49,7 @@ class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase( @Mock private lateinit var mediaProjectionManager: MediaProjectionManager @Mock private lateinit var packageManager: PackageManager @Mock private lateinit var telephonyManager: TelephonyManager + @Mock private lateinit var roleManager: RoleManager private lateinit var controller: SensitiveNotificationProtectionControllerImpl @Before @@ -62,9 +64,10 @@ class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase( activityManager, packageManager, telephonyManager, + roleManager, handler, FakeExecutor(FakeSystemClock()), - logger + logger, ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColorRule.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColorRule.java new file mode 100644 index 000000000000..ecd04a47b8ae --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColorRule.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.theme; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + + +public class HardwareColorRule implements TestRule { + public String color = ""; + public String[] options = {}; + public boolean isTesting = false; + + @Override + public Statement apply(Statement base, Description description) { + HardwareColors hardwareColors = description.getAnnotation(HardwareColors.class); + if (hardwareColors != null) { + color = hardwareColors.color(); + options = hardwareColors.options(); + isTesting = true; + } + return base; + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColors.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColors.java new file mode 100644 index 000000000000..0b8df2e2670e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/HardwareColors.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.theme; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface HardwareColors { + String color(); + String[] options(); +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index 5cd0846ded7e..9a0b8125fb25 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -64,6 +64,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.flags.SystemPropertiesHelper; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.monet.DynamicColors; @@ -77,6 +78,7 @@ import com.android.systemui.util.settings.SecureSettings; import com.google.common.util.concurrent.MoreExecutors; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -98,6 +100,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { private static final UserHandle MANAGED_USER_HANDLE = UserHandle.of(100); private static final UserHandle PRIVATE_USER_HANDLE = UserHandle.of(101); + @Rule + public HardwareColorRule rule = new HardwareColorRule(); + @Mock private JavaAdapter mJavaAdapter; @Mock @@ -148,13 +153,17 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { @Captor private ArgumentCaptor<ContentObserver> mSettingsObserver; + @Mock + private SystemPropertiesHelper mSystemProperties; + @Before public void setup() { MockitoAnnotations.initMocks(this); + when(mFeatureFlags.isEnabled(Flags.MONET)).thenReturn(true); when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE); when(mUiModeManager.getContrast()).thenReturn(0.5f); - when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); + when(mResources.getColor(eq(android.R.color.system_accent1_500), any())) .thenReturn(Color.RED); when(mResources.getColor(eq(android.R.color.system_accent2_500), any())) @@ -166,11 +175,20 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { when(mResources.getColor(eq(android.R.color.system_neutral2_500), any())) .thenReturn(Color.BLACK); + when(mResources.getStringArray(com.android.internal.R.array.theming_defaults)) + .thenReturn(rule.options); + + // should fallback to `*|TONAL_SPOT|home_wallpaper` + when(mSystemProperties.get("ro.boot.hardware.color")).thenReturn(rule.color); + // will try set hardware colors as boot ONLY if user is not set yet + when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(!rule.isTesting); + mThemeOverlayController = new ThemeOverlayController(mContext, mBroadcastDispatcher, mBgHandler, mMainExecutor, mBgExecutor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, - mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager) { + mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager, + mSystemProperties) { @VisibleForTesting protected boolean isNightMode() { return false; @@ -214,11 +232,58 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { public void start_checksWallpaper() { ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class); verify(mBgExecutor).execute(registrationRunnable.capture()); + registrationRunnable.getValue().run(); + verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM)); + } + + @Test + @HardwareColors(color = "BLK", options = { + "BLK|MONOCHROMATIC|#FF0000", + "*|VIBRANT|home_wallpaper" + }) + @EnableFlags(com.android.systemui.Flags.FLAG_HARDWARE_COLOR_STYLES) + public void start_checkHardwareColor() { + // getWallpaperColors should not be called + ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class); + verify(mMainExecutor).execute(registrationRunnable.capture()); + registrationRunnable.getValue().run(); + verify(mWallpaperManager, never()).getWallpaperColors(anyInt()); + + assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.MONOCHROMATIC); + assertThat(mThemeOverlayController.mCurrentColors.get(0).getMainColors().get( + 0).toArgb()).isEqualTo(Color.RED); + } + + @Test + @HardwareColors(color = "", options = { + "BLK|MONOCHROMATIC|#FF0000", + "*|VIBRANT|home_wallpaper" + }) + @EnableFlags(com.android.systemui.Flags.FLAG_HARDWARE_COLOR_STYLES) + public void start_wildcardColor() { + // getWallpaperColors will be called because we srt wildcard to `home_wallpaper` + ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class); + verify(mMainExecutor).execute(registrationRunnable.capture()); + registrationRunnable.getValue().run(); + verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM)); + assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.VIBRANT); + } + + @Test + @HardwareColors(color = "NONEXISTENT", options = {}) + @EnableFlags(com.android.systemui.Flags.FLAG_HARDWARE_COLOR_STYLES) + public void start_fallbackColor() { + // getWallpaperColors will be called because we default color source is `home_wallpaper` + ArgumentCaptor<Runnable> registrationRunnable = ArgumentCaptor.forClass(Runnable.class); + verify(mMainExecutor).execute(registrationRunnable.capture()); registrationRunnable.getValue().run(); verify(mWallpaperManager).getWallpaperColors(eq(WallpaperManager.FLAG_SYSTEM)); + + assertThat(mThemeOverlayController.mThemeStyle).isEqualTo(Style.TONAL_SPOT); } + @Test public void onWallpaperColorsChanged_setsTheme_whenForeground() { // Should ask for a new theme when wallpaper colors change @@ -287,9 +352,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.system_palette\":\"override.package.name\"," - + "\"android.theme.customization.color_source\":\"preset\"}"; + String jsonString = createJsonString(TestColorSource.preset, "override.package.name", + "TONAL_SPOT"); + when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) .thenReturn(jsonString); @@ -313,11 +378,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -348,11 +409,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -381,11 +438,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { // Should ask for a new theme when wallpaper colors change WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"lock_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.lock_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) .thenReturn(jsonString); @@ -404,11 +457,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { // Should ask for a new theme when wallpaper colors change WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"lock_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.lock_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) .thenReturn(jsonString); @@ -455,8 +504,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { @Test public void onSettingChanged_invalidStyle() { when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true); - String jsonString = "{\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.theme_style\":\"some_invalid_name\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper, "A16B00", + "some_invalid_name"); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -473,11 +522,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -506,11 +551,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { // Should ask for a new theme when wallpaper colors change WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) .thenReturn(jsonString); @@ -537,11 +578,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { // Should ask for a new theme when wallpaper colors change WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) .thenReturn(jsonString); @@ -570,11 +607,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -599,7 +632,6 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { } - @Test @EnableFlags(com.android.systemui.shared.Flags.FLAG_NEW_CUSTOMIZATION_PICKER_UI) public void onWallpaperColorsChanged_homeWallpaperWithSameColor_shouldKeepThemeAndReapply() { @@ -608,11 +640,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(0xffa16b00), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -642,11 +670,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -676,11 +700,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -711,11 +731,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(0xffa16b00), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -745,11 +761,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.color_source\":\"home_wallpaper\"," - + "\"android.theme.customization.system_palette\":\"A16B00\"," - + "\"android.theme.customization.accent_color\":\"A16B00\"," - + "\"android.theme.customization.color_index\":\"2\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper); when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) @@ -886,7 +898,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, - mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager) { + mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager, + mSystemProperties) { @VisibleForTesting protected boolean isNightMode() { return false; @@ -926,7 +939,8 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { mBroadcastDispatcher, mBgHandler, executor, executor, mThemeOverlayApplier, mSecureSettings, mWallpaperManager, mUserManager, mDeviceProvisionedController, mUserTracker, mDumpManager, mFeatureFlags, mResources, mWakefulnessLifecycle, - mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager) { + mJavaAdapter, mKeyguardTransitionInteractor, mUiModeManager, mActivityManager, + mSystemProperties) { @VisibleForTesting protected boolean isNightMode() { return false; @@ -992,7 +1006,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { clearInvocations(mThemeOverlayApplier); // Device went to sleep and second set of colors was applied. - mainColors = new WallpaperColors(Color.valueOf(Color.BLUE), + mainColors = new WallpaperColors(Color.valueOf(Color.BLUE), Color.valueOf(Color.RED), null); mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, USER_SYSTEM); @@ -1018,7 +1032,7 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { clearInvocations(mThemeOverlayApplier); // Device went to sleep and second set of colors was applied. - mainColors = new WallpaperColors(Color.valueOf(Color.BLUE), + mainColors = new WallpaperColors(Color.valueOf(Color.BLUE), Color.valueOf(Color.RED), null); mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM, USER_SYSTEM); @@ -1034,8 +1048,9 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), Color.valueOf(Color.BLUE), null); - String jsonString = - "{\"android.theme.customization.system_palette\":\"00FF00\"}"; + String jsonString = createJsonString(TestColorSource.home_wallpaper, "00FF00", + "TONAL_SPOT"); + when(mSecureSettings.getStringForUser( eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt())) .thenReturn(jsonString); @@ -1115,4 +1130,25 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { + DynamicColors.getCustomColorsMapped(false).size() * 2) ).setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null)); } + + private enum TestColorSource { + preset, + home_wallpaper, + lock_wallpaper + } + + private String createJsonString(TestColorSource colorSource, String seedColorHex, + String style) { + return "{\"android.theme.customization.color_source\":\"" + colorSource.toString() + "\"," + + "\"android.theme.customization.system_palette\":\"" + seedColorHex + "\"," + + "\"android.theme.customization.accent_color\":\"" + seedColorHex + "\"," + + "\"android.theme.customization.color_index\":\"2\"," + + "\"android.theme.customization.theme_style\":\"" + style + "\"}"; + } + + private String createJsonString(TestColorSource colorSource) { + return createJsonString(colorSource, "A16B00", "TONAL_SPOT"); + } + + } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt index 36e18e653f20..92bec70d2c4d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/unfold/DisplaySwitchLatencyTrackerTest.kt @@ -173,15 +173,13 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { runCurrent() setDeviceState(UNFOLDED) - verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) - val loggedEvent = loggerArgumentCaptor.value val expectedLoggedEvent = - DisplaySwitchLatencyEvent( + successfulEvent( latencyMs = 250, fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED, toFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN, ) - assertThat(loggedEvent).isEqualTo(expectedLoggedEvent) + assertThat(capturedLogEvent()).isEqualTo(expectedLoggedEvent) } } @@ -225,15 +223,13 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { runCurrent() setDeviceState(UNFOLDED) - verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) - val loggedEvent = loggerArgumentCaptor.value val expectedLoggedEvent = - DisplaySwitchLatencyEvent( + successfulEvent( latencyMs = 50, fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED, toFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN, ) - assertThat(loggedEvent).isEqualTo(expectedLoggedEvent) + assertThat(capturedLogEvent()).isEqualTo(expectedLoggedEvent) } } @@ -258,15 +254,13 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { runCurrent() setDeviceState(UNFOLDED) - verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) - val loggedEvent = loggerArgumentCaptor.value val expectedLoggedEvent = - DisplaySwitchLatencyEvent( + successfulEvent( latencyMs = 50, fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED, toFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN, ) - assertThat(loggedEvent).isEqualTo(expectedLoggedEvent) + assertThat(capturedLogEvent()).isEqualTo(expectedLoggedEvent) } } @@ -287,15 +281,13 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { powerInteractor.setScreenPowerState(SCREEN_ON) runCurrent() - verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) - val loggedEvent = loggerArgumentCaptor.value val expectedLoggedEvent = - DisplaySwitchLatencyEvent( + successfulEvent( latencyMs = 200, fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN, toFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED, ) - assertThat(loggedEvent).isEqualTo(expectedLoggedEvent) + assertThat(capturedLogEvent()).isEqualTo(expectedLoggedEvent) } } @@ -317,16 +309,14 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { powerInteractor.setScreenPowerState(SCREEN_ON) runCurrent() - verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) - val loggedEvent = loggerArgumentCaptor.value val expectedLoggedEvent = - DisplaySwitchLatencyEvent( + successfulEvent( latencyMs = 200, fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN, toFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED, toState = SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__AOD, ) - assertThat(loggedEvent).isEqualTo(expectedLoggedEvent) + assertThat(capturedLogEvent()).isEqualTo(expectedLoggedEvent) } } @@ -369,16 +359,14 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { powerInteractor.setScreenPowerState(SCREEN_OFF) runCurrent() - verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) - val loggedEvent = loggerArgumentCaptor.value val expectedLoggedEvent = - DisplaySwitchLatencyEvent( + successfulEvent( latencyMs = 0, fromFoldableDeviceState = FOLDABLE_DEVICE_STATE_HALF_OPEN, toFoldableDeviceState = FOLDABLE_DEVICE_STATE_CLOSED, toState = SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TO_STATE__SCREEN_OFF, ) - assertThat(loggedEvent).isEqualTo(expectedLoggedEvent) + assertThat(capturedLogEvent()).isEqualTo(expectedLoggedEvent) } } @@ -555,6 +543,23 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { } @Test + fun interruptedDisplaySwitchFinished_coolDownPassed_eventWithCorruptedResultSent() { + testScope.runTest { + startInFoldedState(displaySwitchLatencyTracker) + + startUnfolding() + startFolding() + systemClock.advanceTime(5000) // clock for measuring latency + advanceTimeBy(COOL_DOWN_DURATION.plus(10.milliseconds)) // clock for triggering timeout + + val event = capturedLogEvent() + assertThat(event.trackingResult) + .isEqualTo(SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TRACKING_RESULT__CORRUPTED) + assertThat(event.latencyMs).isEqualTo(5000) + } + } + + @Test fun displaySwitchInterrupted_coolDownExtendedByStartEvents() { testScope.runTest { startInFoldedState(displaySwitchLatencyTracker) @@ -605,6 +610,27 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { } @Test + fun displaySwitchTimedOut_eventLoggedWithTimeOut() { + testScope.runTest { + startInFoldedState(displaySwitchLatencyTracker) + + startUnfolding() + advanceTimeBy(SCREEN_EVENT_TIMEOUT + 10.milliseconds) + finishUnfolding() + + val event = capturedLogEvent() + assertThat(event.trackingResult) + .isEqualTo(SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TRACKING_RESULT__TIMED_OUT) + assertThat(event.latencyMs).isEqualTo(SCREEN_EVENT_TIMEOUT.inWholeMilliseconds) + } + } + + private fun capturedLogEvent(): DisplaySwitchLatencyEvent { + verify(displaySwitchLatencyLogger).log(capture(loggerArgumentCaptor)) + return loggerArgumentCaptor.value + } + + @Test fun foldingStarted_screenStillOn_eventSentOnlyAfterScreenSwitches() { // can happen for both folding and unfolding (with animations off) but it's more likely to // happen when folding as waiting for screen on is the default case then @@ -625,6 +651,21 @@ class DisplaySwitchLatencyTrackerTest : SysuiTestCase() { } } + private fun successfulEvent( + latencyMs: Int, + fromFoldableDeviceState: Int, + toFoldableDeviceState: Int, + toState: Int = SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__FROM_STATE__UNKNOWN, + ): DisplaySwitchLatencyEvent { + return DisplaySwitchLatencyEvent( + latencyMs = latencyMs, + fromFoldableDeviceState = fromFoldableDeviceState, + toFoldableDeviceState = toFoldableDeviceState, + toState = toState, + trackingResult = SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TRACKING_RESULT__SUCCESS, + ) + } + private suspend fun TestScope.startInFoldedState(tracker: DisplaySwitchLatencyTracker) { setDeviceState(FOLDED) tracker.start() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt index 7c166de81502..cc6a7b93eef3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryImplTest.kt @@ -42,7 +42,6 @@ import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any @@ -53,7 +52,6 @@ import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidJUnit4::class) class WallpaperRepositoryImplTest : SysuiTestCase() { - private var isWallpaperSupported = true private val kosmos = testKosmos().apply { @@ -293,12 +291,9 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { Intent(Intent.ACTION_WALLPAPER_CHANGED), ) assertThat(latest).isTrue() - assertThat(underTest.sendLockscreenLayoutJob).isNotNull() - assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true) } @Test - @Ignore("ag/31591766") @EnableFlags(SharedFlags.FLAG_EXTENDED_WALLPAPER_EFFECTS) fun shouldSendNotificationLayout_setNotExtendedEffectsWallpaper_cancelSendLayoutJob() = testScope.runTest { @@ -315,8 +310,6 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { Intent(Intent.ACTION_WALLPAPER_CHANGED), ) assertThat(latest).isTrue() - assertThat(underTest.sendLockscreenLayoutJob).isNotNull() - assertThat(underTest.sendLockscreenLayoutJob!!.isActive).isEqualTo(true) whenever(kosmos.wallpaperManager.getWallpaperInfoForUser(any())) .thenReturn(UNSUPPORTED_WP) @@ -327,7 +320,6 @@ class WallpaperRepositoryImplTest : SysuiTestCase() { runCurrent() assertThat(latest).isFalse() - assertThat(underTest.sendLockscreenLayoutJob?.isCancelled).isEqualTo(true) } private companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt index 31afc298951b..31a611cc984b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractorTest.kt @@ -30,11 +30,8 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.shade.data.repository.shadeRepository -import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.testKosmos -import com.android.systemui.wallpapers.data.repository.fakeWallpaperFocalAreaRepository import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository -import com.android.systemui.wallpapers.data.repository.wallpaperRepository import com.android.systemui.wallpapers.ui.viewmodel.wallpaperFocalAreaViewModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -75,36 +72,22 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { .thenReturn(2f) underTest = WallpaperFocalAreaInteractor( - applicationScope = testScope.backgroundScope, context = kosmos.mockedContext, - wallpaperFocalAreaRepository = kosmos.fakeWallpaperFocalAreaRepository, + wallpaperFocalAreaRepository = kosmos.wallpaperFocalAreaRepository, shadeRepository = kosmos.shadeRepository, - activeNotificationsInteractor = kosmos.activeNotificationsInteractor, - wallpaperRepository = kosmos.wallpaperRepository, ) } - private fun overrideMockedResources(overrideResources: OverrideResources) { - val displayMetrics = - DisplayMetrics().apply { - widthPixels = overrideResources.screenWidth - heightPixels = overrideResources.screenHeight - density = 2f - } - whenever(mockedResources.displayMetrics).thenReturn(displayMetrics) - whenever(mockedResources.getBoolean(R.bool.center_align_focal_area_shape)) - .thenReturn(overrideResources.centerAlignFocalArea) - } - @Test fun focalAreaBounds_withoutNotifications_inHandheldDevices() = testScope.runTest { overrideMockedResources( + mockedResources, OverrideResources( screenWidth = 1000, screenHeight = 2000, centerAlignFocalArea = false, - ) + ), ) val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds) kosmos.shadeRepository.setShadeLayoutWide(false) @@ -120,11 +103,12 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { fun focalAreaBounds_withNotifications_inHandheldDevices() = testScope.runTest { overrideMockedResources( + mockedResources, OverrideResources( screenWidth = 1000, screenHeight = 2000, centerAlignFocalArea = false, - ) + ), ) val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds) kosmos.shadeRepository.setShadeLayoutWide(false) @@ -139,11 +123,12 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { fun focalAreaBounds_inUnfoldLandscape() = testScope.runTest { overrideMockedResources( + mockedResources, OverrideResources( screenWidth = 2000, screenHeight = 1600, centerAlignFocalArea = false, - ) + ), ) val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds) kosmos.shadeRepository.setShadeLayoutWide(true) @@ -158,11 +143,12 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { fun focalAreaBounds_withNotifications_inUnfoldPortrait() = testScope.runTest { overrideMockedResources( + mockedResources, OverrideResources( screenWidth = 1600, screenHeight = 2000, centerAlignFocalArea = false, - ) + ), ) val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds) kosmos.shadeRepository.setShadeLayoutWide(false) @@ -177,11 +163,12 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { fun focalAreaBounds_withoutNotifications_inUnfoldPortrait() = testScope.runTest { overrideMockedResources( + mockedResources, OverrideResources( screenWidth = 1600, screenHeight = 2000, centerAlignFocalArea = false, - ) + ), ) val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds) kosmos.shadeRepository.setShadeLayoutWide(false) @@ -196,11 +183,12 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { fun focalAreaBounds_inTabletLandscape() = testScope.runTest { overrideMockedResources( + mockedResources, OverrideResources( screenWidth = 3000, screenHeight = 2000, centerAlignFocalArea = true, - ) + ), ) val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds) kosmos.shadeRepository.setShadeLayoutWide(true) @@ -216,11 +204,12 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { testScope.runTest { kosmos.wallpaperFocalAreaRepository.setTapPosition(PointF(0F, 0F)) overrideMockedResources( + mockedResources, OverrideResources( screenWidth = 1000, screenHeight = 2000, centerAlignFocalArea = false, - ) + ), ) kosmos.wallpaperFocalAreaRepository.setWallpaperFocalAreaBounds( RectF(250f, 700F, 750F, 1400F) @@ -240,11 +229,12 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { testScope.runTest { kosmos.wallpaperFocalAreaRepository.setTapPosition(PointF(0F, 0F)) overrideMockedResources( + mockedResources, OverrideResources( screenWidth = 1000, screenHeight = 2000, centerAlignFocalArea = false, - ) + ), ) kosmos.wallpaperFocalAreaViewModel = mock() kosmos.wallpaperFocalAreaRepository.setWallpaperFocalAreaBounds( @@ -262,4 +252,21 @@ class WallpaperFocalAreaInteractorTest : SysuiTestCase() { val screenHeight: Int, val centerAlignFocalArea: Boolean, ) + + companion object { + fun overrideMockedResources( + mockedResources: Resources, + overrideResources: OverrideResources, + ) { + val displayMetrics = + DisplayMetrics().apply { + widthPixels = overrideResources.screenWidth + heightPixels = overrideResources.screenHeight + density = 2f + } + whenever(mockedResources.displayMetrics).thenReturn(displayMetrics) + whenever(mockedResources.getBoolean(R.bool.center_align_focal_area_shape)) + .thenReturn(overrideResources.centerAlignFocalArea) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModelTest.kt new file mode 100644 index 000000000000..3cd20721a15b --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModelTest.kt @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wallpapers.ui.viewmodel + +import android.content.mockedContext +import android.content.res.Resources +import android.graphics.RectF +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.shade.data.repository.shadeRepository +import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository +import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs +import com.android.systemui.testKosmos +import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository +import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor +import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractorTest.Companion.overrideMockedResources +import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractorTest.OverrideResources +import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class WallpaperFocalAreaViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var mockedResources: Resources + lateinit var underTest: WallpaperFocalAreaViewModel + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + mockedResources = mock<Resources>() + overrideMockedResources( + mockedResources, + OverrideResources(screenWidth = 1000, screenHeight = 2000, centerAlignFocalArea = false), + ) + whenever(kosmos.mockedContext.resources).thenReturn(mockedResources) + whenever( + mockedResources.getFloat( + Resources.getSystem() + .getIdentifier( + /* name= */ "config_wallpaperMaxScale", + /* defType= */ "dimen", + /* defPackage= */ "android", + ) + ) + ) + .thenReturn(2f) + kosmos.wallpaperFocalAreaInteractor = + WallpaperFocalAreaInteractor( + context = kosmos.mockedContext, + wallpaperFocalAreaRepository = kosmos.wallpaperFocalAreaRepository, + shadeRepository = kosmos.shadeRepository, + ) + underTest = + WallpaperFocalAreaViewModel( + wallpaperFocalAreaInteractor = kosmos.wallpaperFocalAreaInteractor, + keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor, + ) + } + + @Test + fun focalAreaBoundsSent_whenFinishTransitioningToLockscreen() = + testScope.runTest { + overrideMockedResources( + mockedResources, + OverrideResources( + screenWidth = 1600, + screenHeight = 2000, + centerAlignFocalArea = false, + ), + ) + val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds) + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf( + TransitionStep(transitionState = TransitionState.STARTED, to = LOCKSCREEN), + TransitionStep(transitionState = TransitionState.FINISHED, to = LOCKSCREEN), + ), + testScope, + ) + + setTestFocalAreaBounds() + + assertThat(bounds).isEqualTo(RectF(400F, 510F, 1200F, 700F)) + } + + @Test + fun focalAreaBoundsNotSent_whenNotFinishTransitioningToLockscreen() = + testScope.runTest { + overrideMockedResources( + mockedResources, + OverrideResources( + screenWidth = 1600, + screenHeight = 2000, + centerAlignFocalArea = false, + ), + ) + val bounds by collectLastValue(underTest.wallpaperFocalAreaBounds) + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf(TransitionStep(transitionState = TransitionState.STARTED, to = LOCKSCREEN)), + testScope, + ) + setTestFocalAreaBounds() + + assertThat(bounds).isEqualTo(null) + } + + private fun setTestFocalAreaBounds() { + kosmos.shadeRepository.setShadeLayoutWide(false) + kosmos.activeNotificationListRepository.setActiveNotifs(0) + kosmos.wallpaperFocalAreaRepository.setShortcutAbsoluteTop(400F) + kosmos.wallpaperFocalAreaRepository.setNotificationDefaultTop(20F) + kosmos.wallpaperFocalAreaRepository.setNotificationStackAbsoluteBottom(20F) + } +} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java index 94fdbae83253..9b961d2535ae 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java @@ -122,7 +122,7 @@ public interface NotificationMenuRowPlugin extends Plugin { public void setAppName(String appName); - public void createMenu(ViewGroup parent, StatusBarNotification sbn); + public void createMenu(ViewGroup parent); public void resetMenu(); @@ -215,9 +215,8 @@ public interface NotificationMenuRowPlugin extends Plugin { /** * Callback used to signal the menu that its parent notification has been updated. - * @param sbn */ - public void onNotificationUpdated(StatusBarNotification sbn); + public void onNotificationUpdated(); /** * Callback used to signal the menu that a user is moving the parent notification. diff --git a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_confirm.xml b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_confirm.xml index 61d6a9046144..a27e29f1beb6 100644 --- a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_confirm.xml +++ b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_confirm.xml @@ -19,12 +19,13 @@ android:height="40dp" android:viewportHeight="40" android:viewportWidth="40"> + <group> + <clip-path android:pathData="M8,12h24.5v15.5h-24.5z" /> <path - android:fillColor="#F7DAEE" - android:fillType="evenOdd" - android:pathData="M20.76,19C21.65,19 22.096,17.924 21.467,17.294L19.284,15.105C18.895,14.716 18.895,14.085 19.285,13.695C19.674,13.306 20.306,13.306 20.695,13.695L26.293,19.293C26.683,19.683 26.683,20.317 26.293,20.707L20.705,26.295C20.315,26.685 19.683,26.686 19.292,26.298C18.9,25.907 18.898,25.272 19.29,24.88L21.463,22.707C22.093,22.077 21.647,21 20.756,21H10C9.448,21 9,20.552 9,20C9,19.448 9.448,19 10,19H20.76ZM32,26C32,26.552 31.552,27 31,27C30.448,27 30,26.552 30,26V14C30,13.448 30.448,13 31,13C31.552,13 32,13.448 32,14V26Z" - android:strokeColor="#F7DAEE" - android:strokeLineCap="round" - android:strokeLineJoin="round" - android:strokeWidth="2" /> + android:fillColor="#000000" + android:pathData="M30.75,12C29.79,12 29,12.79 29,13.75V25.75C29,26.71 29.79,27.5 30.75,27.5C31.71,27.5 32.5,26.71 32.5,25.75V13.75C32.5,12.79 31.71,12 30.75,12Z" /> + <path + android:fillColor="#000000" + android:pathData="M20.98,12.92C20.3,12.24 19.19,12.24 18.51,12.92C17.83,13.6 17.83,14.71 18.51,15.39L21.12,18H9.75C8.79,18 8,18.79 8,19.75C8,20.71 8.79,21.5 9.75,21.5H21.11L18.51,24.1C18.18,24.43 18,24.87 18,25.34C18,25.81 18.18,26.25 18.52,26.58C18.86,26.92 19.31,27.09 19.75,27.09C20.19,27.09 20.65,26.92 20.99,26.58L26.61,20.96C27.28,20.29 27.28,19.21 26.61,18.55L20.98,12.92Z" /> + </group> </vector> diff --git a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete.xml b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete.xml deleted file mode 100644 index 044656d6fc7d..000000000000 --- a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete.xml +++ /dev/null @@ -1,25 +0,0 @@ -<!-- - ~ Copyright (C) 2025 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="40dp" - android:height="40dp" - android:viewportHeight="40" - android:viewportWidth="40"> - <path - android:fillColor="#ECDFE5" - android:pathData="M18.792,26.5L23.333,21.958L27.875,26.5L29.875,24.542L25.292,20L29.792,15.458L27.833,13.5L23.333,18.042L18.792,13.5L16.792,15.458L21.375,20L16.792,24.542L18.792,26.5ZM14.708,33.333C14.292,33.333 13.875,33.236 13.458,33.042C13.069,32.847 12.75,32.569 12.5,32.208L3.333,20L12.458,7.792C12.708,7.431 13.028,7.153 13.417,6.958C13.833,6.764 14.264,6.667 14.708,6.667H33.917C34.694,6.667 35.347,6.944 35.875,7.5C36.431,8.028 36.708,8.681 36.708,9.458V30.542C36.708,31.319 36.431,31.986 35.875,32.542C35.347,33.069 34.694,33.333 33.917,33.333H14.708Z" /> -</vector> diff --git a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_filled.xml b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_filled.xml new file mode 100644 index 000000000000..86f95bc97169 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_filled.xml @@ -0,0 +1,25 @@ +<!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportHeight="40" + android:viewportWidth="40"> + <path + android:fillColor="#000000" + android:pathData="M22.167,21.9L25.531,25.265C25.795,25.502 26.112,25.621 26.481,25.621C26.851,25.621 27.167,25.502 27.431,25.265C27.669,25.001 27.788,24.684 27.788,24.315C27.788,23.919 27.669,23.589 27.431,23.325L24.067,20L27.392,16.675C27.656,16.411 27.788,16.094 27.788,15.725C27.788,15.356 27.656,15.039 27.392,14.775C27.128,14.511 26.798,14.379 26.402,14.379C26.033,14.379 25.729,14.511 25.492,14.775L22.167,18.1L18.802,14.735C18.538,14.498 18.222,14.379 17.852,14.379C17.483,14.379 17.166,14.498 16.902,14.735C16.665,14.999 16.546,15.329 16.546,15.725C16.546,16.094 16.665,16.411 16.902,16.675L20.267,20L16.902,23.325C16.665,23.589 16.546,23.906 16.546,24.275C16.546,24.644 16.665,24.961 16.902,25.225C17.166,25.489 17.483,25.621 17.852,25.621C18.248,25.621 18.578,25.489 18.842,25.225L22.167,21.9ZM14.012,32.667C13.59,32.667 13.181,32.574 12.785,32.39C12.416,32.179 12.099,31.915 11.835,31.598L4.394,21.623C4.024,21.148 3.84,20.607 3.84,20C3.84,19.393 4.024,18.852 4.394,18.377L11.835,8.402C12.073,8.085 12.39,7.835 12.785,7.65C13.181,7.439 13.59,7.333 14.012,7.333H32.142C32.907,7.333 33.554,7.597 34.081,8.125C34.609,8.653 34.873,9.286 34.873,10.025V29.975C34.873,30.714 34.609,31.347 34.081,31.875C33.554,32.403 32.907,32.667 32.142,32.667H14.012Z" /> +</vector> diff --git a/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_outline.xml b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_outline.xml new file mode 100644 index 000000000000..7f551f4d3c60 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/pin_bouncer_delete_outline.xml @@ -0,0 +1,31 @@ +<!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportHeight="40" + android:viewportWidth="40"> + <group> + <clip-path android:pathData="M5,7h29.89v25h-29.89z" /> + <path + android:fillColor="#000000" + android:pathData="M30.96,32H15.59C14.21,32 12.89,31.34 12.06,30.24L5.78,21.86C4.74,20.47 4.74,18.54 5.78,17.15L12.06,8.77C12.89,7.67 14.21,7 15.59,7H30.96C33.13,7 34.89,8.76 34.89,10.93V28.08C34.89,30.25 33.13,32.01 30.96,32.01V32ZM14.46,28.44C14.73,28.79 15.15,29 15.59,29H30.96C31.47,29 31.89,28.58 31.89,28.07V10.93C31.89,10.42 31.47,10 30.96,10H15.59C15.15,10 14.73,10.21 14.46,10.56L8.18,18.94C7.93,19.27 7.93,19.72 8.18,20.05L14.46,28.43V28.44Z" /> + <path + android:fillColor="#000000" + android:pathData="M22.46,21.27L25.36,24.17C25.6,24.43 25.89,24.56 26.25,24.56C26.61,24.56 26.9,24.43 27.14,24.17C27.4,23.93 27.53,23.64 27.53,23.28C27.53,22.92 27.4,22.63 27.14,22.39L24.24,19.49L27.14,16.59C27.38,16.35 27.49,16.06 27.49,15.7C27.49,15.34 27.37,15.05 27.14,14.81C26.91,14.57 26.61,14.46 26.25,14.46C25.89,14.46 25.59,14.58 25.33,14.81L22.46,17.71L19.56,14.81C19.32,14.55 19.03,14.42 18.67,14.42C18.31,14.42 18.02,14.55 17.78,14.81C17.52,15.05 17.39,15.34 17.39,15.7C17.39,16.06 17.52,16.35 17.78,16.59L20.68,19.49L17.78,22.39C17.52,22.63 17.39,22.92 17.39,23.28C17.39,23.64 17.52,23.93 17.78,24.17C18.02,24.41 18.31,24.52 18.67,24.52C19.03,24.52 19.32,24.4 19.56,24.17L22.46,21.27Z" /> + </group> +</vector> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml index 0b35559148af..87d06bfde743 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml @@ -21,7 +21,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/keyguard_lock_padding" - android:importantForAccessibility="no" + android:accessibilityLiveRegion="polite" android:ellipsize="marquee" android:focusable="false" android:gravity="center" diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml index f231df2f1a10..c7f320c69113 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_motion_layout.xml @@ -67,6 +67,7 @@ <com.android.systemui.bouncer.ui.BouncerMessageView android:id="@+id/bouncer_message_view" android:screenReaderFocusable="true" + android:accessibilityLiveRegion="polite" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml index 04457229d573..9359838238af 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml @@ -32,6 +32,7 @@ <com.android.systemui.bouncer.ui.BouncerMessageView android:id="@+id/bouncer_message_view" android:screenReaderFocusable="true" + android:accessibilityLiveRegion="polite" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml index b184344f2f24..6cbe96a8cb50 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_motion_layout.xml @@ -68,6 +68,7 @@ <com.android.systemui.bouncer.ui.BouncerMessageView android:id="@+id/bouncer_message_view" android:screenReaderFocusable="true" + android:accessibilityLiveRegion="polite" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml index 0e15ff66f3ee..cf388875a174 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml @@ -36,6 +36,7 @@ <com.android.systemui.bouncer.ui.BouncerMessageView android:id="@+id/bouncer_message_view" android:screenReaderFocusable="true" + android:accessibilityLiveRegion="polite" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml index f6ac02aee657..33eab179c3f7 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_motion_layout.xml @@ -75,6 +75,7 @@ <com.android.systemui.bouncer.ui.BouncerMessageView android:id="@+id/bouncer_message_view" android:screenReaderFocusable="true" + android:accessibilityLiveRegion="polite" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml index ba4da794d777..fd5eeb8b9408 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml @@ -33,6 +33,7 @@ <com.android.systemui.bouncer.ui.BouncerMessageView android:id="@+id/bouncer_message_view" android:screenReaderFocusable="true" + android:accessibilityLiveRegion="polite" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml index ea3cbcff8dbe..739e868bb841 100644 --- a/packages/SystemUI/res-keyguard/values-bg/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml @@ -27,7 +27,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Въведете паролата си"</string> <string name="keyguard_enter_password" msgid="6483623792371009758">"Въведете паролата"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Картата е невалидна."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Заредена"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Заредено"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се безжично"</string> <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се"</string> diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml index 226d19375e73..0da063686628 100644 --- a/packages/SystemUI/res-keyguard/values-ca/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml @@ -27,7 +27,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introdueix la contrasenya"</string> <string name="keyguard_enter_password" msgid="6483623792371009758">"Introdueix la contrasenya"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"La targeta no és vàlida."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Bateria carregada"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Carregat"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant sense fil"</string> <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant"</string> diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml index 0b8ad027e6d9..0913f72bc786 100644 --- a/packages/SystemUI/res-keyguard/values-et/strings.xml +++ b/packages/SystemUI/res-keyguard/values-et/strings.xml @@ -62,9 +62,9 @@ <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Proovige uuesti või sisestage PIN-kood"</string> <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Proovige uuesti või sisestage parool"</string> <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Proovige uuesti või joonistage muster"</string> - <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN-koodi nõutakse pärast liiga paljusid katseid"</string> + <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN-koodi nõutakse pärast liiga paljusid katseid."</string> <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Parool on nõutav pärast liiga paljusid katseid"</string> - <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Muster on nõutav pärast liiga paljusid katseid"</string> + <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Muster on nõutav pärast liiga paljusid katseid."</string> <string name="kg_unlock_with_pin_or_fp" msgid="5635161174698729890">"Avage PIN-koodi või sõrmejäljega"</string> <string name="kg_unlock_with_password_or_fp" msgid="2251295907826814237">"Avage parooli või sõrmejäljega"</string> <string name="kg_unlock_with_pattern_or_fp" msgid="2391870539909135046">"Avage mustri või sõrmejäljega"</string> diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml index 103f8ad9e84c..c3fccf2da8d6 100644 --- a/packages/SystemUI/res-keyguard/values-kk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml @@ -36,7 +36,7 @@ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяны қорғау мақсатында зарядтау кідіртілді."</string> <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядтау құрылғысын тексеріңіз."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Желі құлыптаулы"</string> - <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM картасы жоқ."</string> + <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM картасы жоқ"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM картасын пайдалану мүмкін емес."</string> <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM картасы құлыпталған."</string> <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM картасы PUK кодымен құлыпталды."</string> diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml index 9a26f7d7b8e9..1bdfd42ea1a2 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml @@ -27,7 +27,7 @@ <string name="keyguard_enter_your_password" msgid="7225626204122735501">"Introduza a palavra-passe"</string> <string name="keyguard_enter_password" msgid="6483623792371009758">"Introduza a palavra-passe"</string> <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Cartão inválido."</string> - <string name="keyguard_charged" msgid="5478247181205188995">"Carregada"</string> + <string name="keyguard_charged" msgid="5478247181205188995">"Bateria carregada"</string> <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar sem fios"</string> <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar"</string> <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar…"</string> diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml index cf2057cafb8b..cab9cb950169 100644 --- a/packages/SystemUI/res-keyguard/values-ru/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml @@ -36,7 +36,7 @@ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядка приостановлена для защиты батареи."</string> <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверьте зарядное устройство."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сеть заблокирована"</string> - <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM-карта отсутствует"</string> + <string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Нет SIM-карты"</string> <string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-карту невозможно использовать."</string> <string name="keyguard_sim_locked_message" msgid="7095293254587575270">"SIM-карта заблокирована."</string> <string name="keyguard_sim_puk_locked_message" msgid="2503428315518592542">"SIM-карта заблокирована с помощью PUK-кода."</string> diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml index bc047be3980e..6dcc65e63604 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml @@ -46,9 +46,9 @@ <string name="keyguard_accessibility_sim_pin_area" msgid="6272116591533888062">"SIM 卡 PIN 區"</string> <string name="keyguard_accessibility_sim_puk_area" msgid="5537294043180237374">"SIM 卡 PUK 區"</string> <string name="keyboardview_keycode_delete" msgid="8489719929424895174">"刪除"</string> - <string name="disable_carrier_button_text" msgid="7153361131709275746">"停用 eSIM 卡"</string> - <string name="error_disable_esim_title" msgid="3802652622784813119">"無法停用 eSIM 卡"</string> - <string name="error_disable_esim_msg" msgid="2441188596467999327">"發生錯誤,因此無法停用 eSIM 卡。"</string> + <string name="disable_carrier_button_text" msgid="7153361131709275746">"停用 eSIM"</string> + <string name="error_disable_esim_title" msgid="3802652622784813119">"無法停用 eSIM"</string> + <string name="error_disable_esim_msg" msgid="2441188596467999327">"發生錯誤,因此無法停用 eSIM。"</string> <string name="keyboardview_keycode_enter" msgid="6727192265631761174">"Enter 鍵"</string> <string name="kg_wrong_pattern" msgid="5907301342430102842">"圖案錯誤"</string> <string name="kg_wrong_pattern_try_again" msgid="3603524940234151881">"解鎖圖案錯誤,請再試一次。"</string> @@ -86,7 +86,7 @@ <string name="kg_too_many_failed_attempts_countdown" msgid="2038195171919795529">"{count,plural, =1{請於 # 秒後再試一次。}other{請於 # 秒後再試一次。}}"</string> <string name="kg_sim_pin_instructions" msgid="1942424305184242951">"輸入 SIM 卡的 PIN 碼。"</string> <string name="kg_sim_pin_instructions_multi" msgid="3639863309953109649">"輸入「<xliff:g id="CARRIER">%1$s</xliff:g>」SIM 卡的 PIN 碼。"</string> - <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g>停用 eSIM 卡即可在沒有行動服務的情況下使用裝置。"</string> + <string name="kg_sim_lock_esim_instructions" msgid="5577169988158738030">"<xliff:g id="PREVIOUS_MSG">%1$s</xliff:g>停用 eSIM 即可在沒有行動服務的情況下使用裝置。"</string> <string name="kg_puk_enter_puk_hint" msgid="3005288372875367017">"SIM 卡已遭停用,輸入 PUK 碼即可繼續使用。如需瞭解詳情,請與電信業者聯絡。"</string> <string name="kg_puk_enter_puk_hint_multi" msgid="4876780689904862943">"SIM 卡「<xliff:g id="CARRIER">%1$s</xliff:g>」現已遭停用,輸入 PUK 碼即可繼續使用。如需瞭解詳情,請與電信業者聯絡。"</string> <string name="kg_puk_enter_pin_hint" msgid="6028432138916150399">"輸入所需的 PIN 碼"</string> diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index bfb37a0d97a7..6d446453d9f7 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -31,6 +31,10 @@ <!-- height for the keyguard pin input field --> <dimen name="keyguard_pin_field_height">56dp</dimen> + <dimen name="keyguard_pattern_dot_size">16dp</dimen> + <dimen name="keyguard_pattern_activated_dot_size">24dp</dimen> + <dimen name="keyguard_pattern_stroke_width">32dp</dimen> + <!-- height for the keyguard password input field --> <dimen name="keyguard_password_field_height">56dp</dimen> diff --git a/packages/SystemUI/res/color/media_player_outline_button_bg.xml b/packages/SystemUI/res/color/media_player_outline_button_bg.xml deleted file mode 100644 index ba7848a5d23e..000000000000 --- a/packages/SystemUI/res/color/media_player_outline_button_bg.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<selector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/colorAccentPrimaryVariant"/> -</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/color/media_player_solid_button_bg.xml b/packages/SystemUI/res/color/media_player_solid_button_bg.xml index 69c971188d34..cc54fa3162cc 100644 --- a/packages/SystemUI/res/color/media_player_solid_button_bg.xml +++ b/packages/SystemUI/res/color/media_player_solid_button_bg.xml @@ -15,7 +15,6 @@ ~ limitations under the License. --> -<selector xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> - <item android:color="?androidprv:attr/colorAccentPrimary"/> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:color="@android:color/system_primary_dark"/> </selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml b/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml new file mode 100644 index 000000000000..4e402cf530e4 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_legacy_speaker_mute.xml @@ -0,0 +1,25 @@ +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?android:attr/textColorPrimary" + android:autoMirrored="true"> + <path android:fillColor="#FFFFFFFF" + android:pathData="M19.8,22.6 L16.775,19.575Q16.15,19.975 15.45,20.263Q14.75,20.55 14,20.725V18.675Q14.35,18.55 14.688,18.425Q15.025,18.3 15.325,18.125L12,14.8V20L7,15H3V9H6.2L1.4,4.2L2.8,2.8L21.2,21.2ZM19.6,16.8 L18.15,15.35Q18.575,14.575 18.788,13.725Q19,12.875 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,13.3 20.638,14.525Q20.275,15.75 19.6,16.8ZM16.25,13.45 L14,11.2V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,12.375 16.438,12.738Q16.375,13.1 16.25,13.45ZM12,9.2 L9.4,6.6 12,4ZM10,15.15V12.8L8.2,11H5V13H7.85ZM9.1,11.9Z"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml b/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml new file mode 100644 index 000000000000..2a90e051b83b --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_legacy_speaker_on.xml @@ -0,0 +1,25 @@ +<!-- + ~ Copyright (C) 2022 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?android:attr/textColorPrimary" + android:autoMirrored="true"> + <path android:fillColor="#FFFFFFFF" + android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,13.275 15.838,14.362Q15.175,15.45 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml new file mode 100644 index 000000000000..b18e0a7aae60 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_legacy_volume_ringer_vibrate.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2017 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="19dp" + android:width="19dp" + android:viewportHeight="24.0" + android:viewportWidth="24.0" + android:tint="?android:attr/textColorPrimary"> + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/> + +</vector> diff --git a/packages/SystemUI/res/drawable/ic_speaker_mute.xml b/packages/SystemUI/res/drawable/ic_speaker_mute.xml index 4e402cf530e4..bf31580f3bb0 100644 --- a/packages/SystemUI/res/drawable/ic_speaker_mute.xml +++ b/packages/SystemUI/res/drawable/ic_speaker_mute.xml @@ -1,5 +1,5 @@ <!-- - ~ Copyright (C) 2022 The Android Open Source Project + ~ Copyright (C) 2025 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. @@ -14,12 +14,15 @@ ~ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24" - android:tint="?android:attr/textColorPrimary" - android:autoMirrored="true"> - <path android:fillColor="#FFFFFFFF" - android:pathData="M19.8,22.6 L16.775,19.575Q16.15,19.975 15.45,20.263Q14.75,20.55 14,20.725V18.675Q14.35,18.55 14.688,18.425Q15.025,18.3 15.325,18.125L12,14.8V20L7,15H3V9H6.2L1.4,4.2L2.8,2.8L21.2,21.2ZM19.6,16.8 L18.15,15.35Q18.575,14.575 18.788,13.725Q19,12.875 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,13.3 20.638,14.525Q20.275,15.75 19.6,16.8ZM16.25,13.45 L14,11.2V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,12.375 16.438,12.738Q16.375,13.1 16.25,13.45ZM12,9.2 L9.4,6.6 12,4ZM10,15.15V12.8L8.2,11H5V13H7.85ZM9.1,11.9Z"/> -</vector>
\ No newline at end of file + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <group> + <clip-path + android:pathData="M0,0h20v20h-20z"/> + <path + android:pathData="M16,18.125L13.771,15.896C13.465,16.09 13.097,16.278 12.667,16.458C12.25,16.625 11.861,16.75 11.5,16.833V15.292C11.667,15.222 11.861,15.146 12.083,15.063C12.319,14.965 12.514,14.875 12.667,14.792L10,12.125V16.021L6,12.021H3V8.021H5.875L1.875,4L2.938,2.938L17.063,17.063L16,18.125ZM15.875,13.771L14.792,12.688C15.014,12.285 15.188,11.861 15.313,11.417C15.438,10.958 15.5,10.493 15.5,10.021C15.5,8.785 15.125,7.688 14.375,6.729C13.639,5.757 12.681,5.09 11.5,4.729V3.188C13.125,3.507 14.444,4.313 15.458,5.604C16.486,6.896 17,8.368 17,10.021C17,10.688 16.903,11.34 16.708,11.979C16.514,12.604 16.236,13.201 15.875,13.771ZM13.292,11.188L11.5,9.396V6.854C12.125,7.132 12.611,7.563 12.958,8.146C13.319,8.715 13.5,9.34 13.5,10.021C13.5,10.215 13.486,10.41 13.458,10.604C13.431,10.799 13.375,10.993 13.292,11.188ZM10,7.896L8.063,5.958L10,4.021V7.896Z" + android:fillColor="#ECDFE5"/> + </group> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_speaker_on.xml b/packages/SystemUI/res/drawable/ic_speaker_on.xml index 2a90e051b83b..f0d057e1b093 100644 --- a/packages/SystemUI/res/drawable/ic_speaker_on.xml +++ b/packages/SystemUI/res/drawable/ic_speaker_on.xml @@ -1,5 +1,5 @@ <!-- - ~ Copyright (C) 2022 The Android Open Source Project + ~ Copyright (C) 2025 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. @@ -14,12 +14,15 @@ ~ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24" - android:tint="?android:attr/textColorPrimary" - android:autoMirrored="true"> - <path android:fillColor="#FFFFFFFF" - android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.175,8.5 15.838,9.6Q16.5,10.7 16.5,12Q16.5,13.275 15.838,14.362Q15.175,15.45 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/> -</vector>
\ No newline at end of file + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <group> + <clip-path + android:pathData="M0,0h20v20h-20z"/> + <path + android:pathData="M11.5,16.833V15.271C12.694,14.951 13.66,14.306 14.396,13.333C15.132,12.347 15.5,11.236 15.5,10C15.5,8.764 15.125,7.667 14.375,6.708C13.639,5.736 12.681,5.069 11.5,4.708V3.146C13.111,3.493 14.431,4.306 15.458,5.583C16.486,6.861 17,8.326 17,9.979C17,11.632 16.486,13.104 15.458,14.396C14.444,15.674 13.125,16.486 11.5,16.833ZM3,11.979V7.979H6L10,3.979V15.979L6,11.979H3ZM11.5,13.125V6.833C12.125,7.111 12.611,7.535 12.958,8.104C13.319,8.674 13.5,9.299 13.5,9.979C13.5,10.66 13.319,11.285 12.958,11.854C12.611,12.41 12.125,12.833 11.5,13.125Z" + android:fillColor="#ECDFE5"/> + </group> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml index b18e0a7aae60..2cbbb0da8de7 100644 --- a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml +++ b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml @@ -1,27 +1,28 @@ <!-- - Copyright (C) 2017 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:height="19dp" - android:width="19dp" - android:viewportHeight="24.0" - android:viewportWidth="24.0" - android:tint="?android:attr/textColorPrimary"> - + android:width="20dp" + android:height="20dp" + android:viewportWidth="20" + android:viewportHeight="20"> + <group> + <clip-path + android:pathData="M0,0h20v20h-20z"/> <path - android:fillColor="#FFFFFFFF" - android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/> - + android:pathData="M0,12.5V7.5H1.5V12.5H0ZM2.5,14V6H4V14H2.5ZM18.5,12.5V7.5H20V12.5H18.5ZM16,14V6H17.5V14H16ZM6.5,17C6.083,17 5.729,16.854 5.438,16.563C5.146,16.271 5,15.917 5,15.5V4.5C5,4.083 5.146,3.729 5.438,3.438C5.729,3.146 6.083,3 6.5,3H13.5C13.917,3 14.271,3.146 14.563,3.438C14.854,3.729 15,4.083 15,4.5V15.5C15,15.917 14.854,16.271 14.563,16.563C14.271,16.854 13.917,17 13.5,17H6.5Z" + android:fillColor="#ECDFE5"/> + </group> </vector> diff --git a/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml b/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml new file mode 100644 index 000000000000..7b55b3c6fb56 --- /dev/null +++ b/packages/SystemUI/res/drawable/mobile_network_type_background_updated.xml @@ -0,0 +1,30 @@ +<?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. + ~ + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle" + > + <corners + android:topLeftRadius="0dp" + android:topRightRadius="@dimen/status_bar_mobile_container_corner_radius_updated" + android:bottomRightRadius="0dp" + android:bottomLeftRadius="@dimen/status_bar_mobile_container_corner_radius_updated"/> + <solid android:color="#FFF" /> + <padding + android:left="2sp" + android:right="2sp"/> +</shape> diff --git a/packages/SystemUI/res/drawable/qs_media_art_background.xml b/packages/SystemUI/res/drawable/qs_media_art_background.xml index 95a187094113..e59f82b77908 100644 --- a/packages/SystemUI/res/drawable/qs_media_art_background.xml +++ b/packages/SystemUI/res/drawable/qs_media_art_background.xml @@ -15,6 +15,7 @@ ~ limitations under the License --> <shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <corners android:radius="@dimen/qs_media_album_radius"/> + android:shape="rectangle"> + <solid android:color="#FF000000" /> + <corners android:radius="@dimen/notification_corner_radius"/> </shape> diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml index b83f15a1a247..c0cb5ef61ca8 100644 --- a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml +++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml @@ -14,4 +14,4 @@ Copyright (C) 2015 The Android Open Source Project limitations under the License. --> <inset xmlns:android="http://schemas.android.com/apk/res/android" - android:drawable="@drawable/ic_speaker_mute" /> + android:drawable="@drawable/ic_legacy_speaker_mute" /> diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml index 21a4c1703d31..4d68d674c259 100644 --- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml +++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml @@ -16,4 +16,4 @@ <inset xmlns:android="http://schemas.android.com/apk/res/android" android:insetLeft="2.5dp" android:insetRight="2.5dp" - android:drawable="@drawable/ic_volume_ringer_vibrate" />
\ No newline at end of file + android:drawable="@drawable/ic_legacy_volume_ringer_vibrate" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml index 1f937174dea3..795b7b4aed35 100644 --- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml +++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml @@ -121,8 +121,8 @@ android:contentDescription="@string/turn_on_bluetooth" android:switchMinWidth="@dimen/settingslib_switch_track_width" android:theme="@style/MainSwitch.Settingslib" - android:thumb="@drawable/settingslib_thumb_selector" - android:track="@drawable/settingslib_track_selector" + android:thumb="@drawable/settingslib_switch_thumb" + android:track="@drawable/settingslib_switch_track" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/bluetooth_toggle_title" app:layout_constraintTop_toTopOf="parent" /> @@ -163,8 +163,8 @@ android:contentDescription="@string/turn_on_bluetooth_auto_tomorrow" android:switchMinWidth="@dimen/settingslib_switch_track_width" android:theme="@style/MainSwitch.Settingslib" - android:thumb="@drawable/settingslib_thumb_selector" - android:track="@drawable/settingslib_track_selector" + android:thumb="@drawable/settingslib_switch_thumb" + android:track="@drawable/settingslib_switch_track" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/bluetooth_auto_on_toggle_title" app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle" /> diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index 5922a7dcdcf0..67e97010ff22 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -131,7 +131,7 @@ style="@style/InternetDialog.Network"> <FrameLayout - android:layout_width="24dp" + android:layout_width="wrap_content" android:layout_height="24dp" android:clickable="false" android:layout_gravity="center_vertical|start"> diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid.xml b/packages/SystemUI/res/layout/notification_2025_hybrid.xml index 8fd10fb3ddb8..8c34cd4165e0 100644 --- a/packages/SystemUI/res/layout/notification_2025_hybrid.xml +++ b/packages/SystemUI/res/layout/notification_2025_hybrid.xml @@ -29,7 +29,6 @@ android:layout_height="wrap_content" android:singleLine="true" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" - android:textSize="@*android:dimen/notification_2025_title_text_size" android:paddingEnd="4dp" /> <TextView diff --git a/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml index 35f2ef901bdd..a338e4c70cfa 100644 --- a/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml +++ b/packages/SystemUI/res/layout/notification_2025_hybrid_conversation.xml @@ -54,7 +54,6 @@ android:singleLine="true" android:paddingEnd="4dp" android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" - android:textSize="@*android:dimen/notification_2025_title_text_size" /> <TextView diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 889aefed0c5c..f41eaec8e18b 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -13,14 +13,13 @@ See the License for the specific language governing permissions and limitations under the License. --> -<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/volume_dialog" android:layout_width="match_parent" android:layout_height="match_parent" android:alpha="0" - android:clipChildren="false" - app:layoutDescription="@xml/volume_dialog_scene"> + android:clipChildren="false"> <View android:id="@+id/volume_dialog_background" @@ -52,7 +51,17 @@ <include android:id="@+id/volume_dialog_main_slider_container" - layout="@layout/volume_dialog_slider" /> + layout="@layout/volume_dialog_slider" + android:layout_width="@dimen/volume_dialog_slider_width" + android:layout_height="0dp" + android:layout_marginTop="@dimen/volume_dialog_slider_vertical_margin" + android:layout_marginEnd="@dimen/volume_dialog_window_margin" + android:layout_marginBottom="@dimen/volume_dialog_slider_vertical_margin" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHeight_max="@dimen/volume_dialog_slider_height" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.5" /> <FrameLayout android:id="@+id/volume_dialog_bottom_section_container" @@ -88,4 +97,4 @@ app:layout_constraintEnd_toStartOf="@id/volume_dialog_background" app:layout_constraintTop_toTopOf="@id/volume_dialog_main_slider_container" /> -</androidx.constraintlayout.motion.widget.MotionLayout> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml b/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml index 0efbc6d651dc..c7e0f7d337c0 100644 --- a/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml +++ b/packages/SystemUI/res/layout/volume_ringer_drawer_legacy.xml @@ -67,7 +67,7 @@ android:layout_width="@dimen/volume_ringer_drawer_icon_size" android:layout_height="@dimen/volume_ringer_drawer_icon_size" android:layout_gravity="center" - android:src="@drawable/ic_volume_ringer_vibrate" + android:src="@drawable/ic_legacy_volume_ringer_vibrate" android:tint="?android:attr/textColorPrimary" /> </FrameLayout> @@ -85,7 +85,7 @@ android:layout_width="@dimen/volume_ringer_drawer_icon_size" android:layout_height="@dimen/volume_ringer_drawer_icon_size" android:layout_gravity="center" - android:src="@drawable/ic_speaker_mute" + android:src="@drawable/ic_legacy_speaker_mute" android:tint="?android:attr/textColorPrimary" /> </FrameLayout> @@ -103,7 +103,7 @@ android:layout_width="@dimen/volume_ringer_drawer_icon_size" android:layout_height="@dimen/volume_ringer_drawer_icon_size" android:layout_gravity="center" - android:src="@drawable/ic_speaker_on" + android:src="@drawable/ic_legacy_speaker_on" android:tint="?android:attr/textColorPrimary" /> </FrameLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index b8b69b6ea992..538d9e23e5c2 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ontkies legstuk"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Verminder hoogte"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Vermeerder hoogte"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Wys volgende"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Wys vorige"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Sluitskermlegstukke"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Om ’n app met ’n legstuk oop te maak, sal jy moet verifieer dat dit jy is. Hou ook in gedagte dat enigeen dit kan bekyk, selfs wanneer jou tablet gesluit is. Sommige legstukke is moontlik nie vir jou sluitskerm bedoel nie en dit kan onveilig wees om dit hier by te voeg."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Het dit"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekskenmerke nie"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Terugvoer"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Maak toe"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Moenie weer wys nie"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Oproepkennisgewings kan nie gewysig word nie."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Hierdie groep kennisgewings kan nie hier opgestel word nie"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Voubare toestel word ontvou"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Voubare toestel word omgekeer"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Voorste skerm is aangeskakel"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Gly om binneskerm te gebruik"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gevou"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"oopgevou"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-af/tiles_states_strings.xml b/packages/SystemUI/res/values-af/tiles_states_strings.xml index fbeefc83c43d..3d0dbb59ddaf 100644 --- a/packages/SystemUI/res/values-af/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-af/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Af"</item> <item msgid="5908720590832378783">"Aan"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index c89ea75ad4cd..f1b9fca25975 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ምግብር አትምረጥ"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ቁመት ቀንስ"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ቁመት ጨምር"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"ቀጣይ አሳይ"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"ቀዳሚ አሳይ"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"የማያ ገፅ ቁልፍ ምግብሮች"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ምግብር በመጠቀም መተግበሪያ ለመክፈት እርስዎ መሆንዎን ማረጋገጥ አለብዎት። እንዲሁም የእርስዎ ጡባዊ በተቆለፈበት ጊዜ እንኳን ማንኛውም ሰው እነሱን ማየት እንደሚችል ከግምት ውስጥ ያስገቡ። አንዳንድ ምግብሮች ለማያ ገፅ ቁልፍዎ የታሰቡ ላይሆኑ ይችላሉ እና እዚህ ለማከል አስተማማኝ ላይሆኑ ይችላሉ።"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ገባኝ"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> የውይይት ባህሪያትን አይደግፍም"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ግብረመልስ"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"አሰናብት"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ዳግም አታሳይ"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"እነዚህ ማሳወቂያዎች ሊሻሻሉ አይችሉም።"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"የጥሪ ማሳወቂያዎች ሊቀየሩ አይችሉም።"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"የማሳወቂያዎች ይህ ቡድን እዚህ ላይ ሊዋቀር አይችልም"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"መታጠፍ የሚችል መሣሪያ እየተዘረጋ ነው"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"መታጠፍ የሚችል መሣሪያ እየተገለበጠ ነው"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"የፊት ለፊት ማያ ገፅ በርቷል"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"ውስጣዊ ማያ ገፅን ለመጠቀም ያንሸራትቱ"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"የታጠፈ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"የተዘረጋ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-am/tiles_states_strings.xml b/packages/SystemUI/res/values-am/tiles_states_strings.xml index b98fe57c232e..31a7d962f39a 100644 --- a/packages/SystemUI/res/values-am/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-am/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ጠፍቷል"</item> <item msgid="5908720590832378783">"በርቷል"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 962f1c954a31..7d55b85db2bb 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"إلغاء اختيار التطبيق المصغّر"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"تقليل الارتفاع"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"زيادة الارتفاع"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"عرض التالي"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"عرض السابق"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"التطبيقات المصغّرة المصمَّمة لشاشة القفل"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"لفتح تطبيق باستخدام تطبيق مصغَّر، عليك إثبات هويتك. يُرجى ملاحظة أنّ أي شخص يمكنه الاطّلاع محتوى التطبيقات المصغَّرة، حتى وإن كان جهازك اللوحي مُقفلاً. بعض التطبيقات المصغّرة قد لا تكون مُصمَّمة لإضافتها إلى شاشة القفل، وقد يكون هذا الإجراء غير آمن."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"حسنًا"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> ميزات المحادثات."</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"الملاحظات"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"إغلاق"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"عدم الإظهار مرة أخرى"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"لا يمكن تعديل إشعارات المكالمات."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"يتعذّر ضبط مجموعة الإشعارات هذه هنا."</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"جهاز قابل للطي يجري فتحه"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"جهاز قابل للطي يجري قلبه"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"تم تفعيل الشاشة الأمامية"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"يُرجى التمرير لاستخدام الشاشة الداخلية"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"مطوي"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"غير مطوي"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> @@ -1525,7 +1531,7 @@ <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"الإضاءة الخلفية للوحة المفاتيح"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"مستوى الإضاءة: %1$d من %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"إدارة المنزل آليًّا"</string> - <string name="home_controls_dream_description" msgid="4644150952104035789">"يمكنك إدارة المنزل آليًّا بشكل سريع من شاشة الاستراحة"</string> + <string name="home_controls_dream_description" msgid="4644150952104035789">"يمكنك إدارة المنزل آليًّا بسرعة من شاشة الاستراحة."</string> <string name="volume_undo_action" msgid="5815519725211877114">"تراجع"</string> <string name="back_edu_toast_content" msgid="4530314597378982956">"للرجوع، مرِّر سريعًا لليمين أو لليسار على لوحة اللمس باستخدام 3 أصابع"</string> <string name="home_edu_toast_content" msgid="3381071147871955415">"للانتقال إلى الشاشة الرئيسية، مرِّر سريعًا للأعلى على لوحة اللمس باستخدام 3 أصابع"</string> diff --git a/packages/SystemUI/res/values-ar/tiles_states_strings.xml b/packages/SystemUI/res/values-ar/tiles_states_strings.xml index 0be4367ae144..abb0d85ea1fb 100644 --- a/packages/SystemUI/res/values-ar/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ar/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"متوقّفة"</item> <item msgid="5908720590832378783">"مفعّلة"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index b88e9e97fae1..74c4e3e17982 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ৱিজেট বাছনিৰ পৰা আঁতৰাওক"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"উচ্চতা হ্ৰাস কৰক"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"উচ্চতা বৃদ্ধি কৰক"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"পিছৰটো দেখুৱাওক"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"পূৰ্বৰটো দেখুৱাওক"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"লক স্ক্ৰীন ৱিজেট"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"এটা ৱিজেট ব্যৱহাৰ কৰি কোনো এপ্ খুলিবলৈ, এয়া আপুনিয়েই বুলি সত্যাপন পৰীক্ষা কৰিব লাগিব। লগতে, মনত ৰাখিব যে যিকোনো লোকেই সেইবোৰ চাব পাৰে, আনকি আপোনাৰ টেবলেটটো লক হৈ থাকিলেও। কিছুমান ৱিজেট হয়তো আপোনাৰ লক স্ক্ৰীনৰ বাবে কৰা হোৱা নাই আৰু ইয়াত যোগ কৰাটো অসুৰক্ষিত হ’ব পাৰে।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"বুজি পালোঁ"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপৰ সুবিধাসমূহ সমৰ্থন নকৰে"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"মতামত"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"অগ্ৰাহ্য কৰক"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"পুনৰাই নেদেখুৱাব"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"কলৰ জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"এই ধৰণৰ জাননীবোৰ ইয়াত কনফিগাৰ কৰিব পৰা নাযায়"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"জপাব পৰা ডিভাইচৰ জাপ খুলি থকা হৈছে"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"জপাব পৰা ডিভাইচৰ ওলোটাই থকা হৈছে"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"সন্মুখৰ স্ক্ৰীনখন অন কৰা হৈছে"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"ভিতৰৰ স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ স্লাইড কৰক"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফ’ল্ড কৰা"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"আনফ’ল্ড কৰা"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-as/tiles_states_strings.xml b/packages/SystemUI/res/values-as/tiles_states_strings.xml index da237e51101e..68212e0163b6 100644 --- a/packages/SystemUI/res/values-as/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-as/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"অফ আছে"</item> <item msgid="5908720590832378783">"অন আছে"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index e629969acd10..4b316b67bb7a 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"vidcet seçimini silin"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Hündürlüyü azaldın"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Hündürlüyü artırın"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Növbətini göstərin"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Əvvəlkini göstərin"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Kilid ekranı vidcetləri"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Vidcetdən istifadə edərək tətbiqi açmaq üçün kimliyi doğrulamalısınız. Planşet kilidli olsa da, hər kəs vidcetlərə baxa bilər. Bəzi vidcetlər kilid ekranı üçün nəzərdə tutulmayıb və bura əlavə etmək təhlükəli ola bilər."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Anladım"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbət funksiyalarını dəstəkləmir"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Rəy"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Rədd edin"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Yenidən göstərməyin"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Zəng bildirişləri dəyişdirilə bilməz."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildiriş qrupunu burada konfiqurasiya etmək olmaz"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Qatlana bilən cihaz açılır"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Qatlana bilən cihaz fırladılır"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ön ekran aktiv edildi"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Daxili ekrandan istifadə etmək üçün sürüşdürün"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"qatlanmış"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"açıq"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-az/tiles_states_strings.xml b/packages/SystemUI/res/values-az/tiles_states_strings.xml index 0203fb08ba6a..696fad22a991 100644 --- a/packages/SystemUI/res/values-az/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-az/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Deaktiv"</item> <item msgid="5908720590832378783">"Aktiv"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 1970144f74c6..9a5bc490764c 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"poništi izbor vidžeta"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Smanji visinu"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Povećaj visinu"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Prikažite sledeće"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Prikažite prethodno"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Vidžeti za zaključani ekran"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da biste otvorili aplikaciju koja koristi vidžet, treba da potvrdite da ste to vi. Imajte u vidu da svako može da ga vidi, čak i kada je tablet zaključan. Neki vidžeti možda nisu namenjeni za zaključani ekran i možda nije bezbedno da ih tamo dodate."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Važi"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije konverzacije"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Povratne informacije"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Odbaci"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne prikazuj ponovo"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obaveštenja o pozivima ne mogu da se menjaju."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ova grupa obaveštenja ne može da se konfiguriše ovde"</string> @@ -1370,7 +1377,7 @@ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Promenite izlaz"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Nepoznato"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"s:min"</string> - <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"č:min"</string> + <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="log_access_confirmation_title" msgid="4843557604739943395">"Želite da dozvolite da <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> pristupa svim evidencijama uređaja?"</string> <string name="log_access_confirmation_allow" msgid="752147861593202968">"Dozvoli jednokratan pristup"</string> <string name="log_access_confirmation_deny" msgid="2389461495803585795">"Ne dozvoli"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml index 2401e4a2fc37..3b9901937dd3 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Isključeno"</item> <item msgid="5908720590832378783">"Uključeno"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index afbac9f8be09..5fc56bc798c8 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"скасаваць выбар віджэта"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Паменшыць вышыню"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Павялічыць вышыню"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Паказаць наступны"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Паказаць папярэдні"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Віджэты на экране блакіроўкі"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Каб адкрыць праграму з дапамогай віджэта, вам неабходна будзе пацвердзіць сваю асобу. Таксама памятайце, што такія віджэты могуць пабачыць іншыя людзі, нават калі экран планшэта заблакіраваны. Некаторыя віджэты могуць не падыходзіць для выкарыстання на экране блакіроўкі, і дадаваць іх сюды можа быць небяспечна."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Зразумела"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае функцыі размовы"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Водгук"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Закрыць"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Больш не паказваць"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Апавяшчэнні пра выклікі нельга змяніць."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Тут канфігурыраваць гэту групу апавяшчэнняў забаронена"</string> diff --git a/packages/SystemUI/res/values-be/tiles_states_strings.xml b/packages/SystemUI/res/values-be/tiles_states_strings.xml index 2dc705772c6c..9f520da995ff 100644 --- a/packages/SystemUI/res/values-be/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-be/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Выключана"</item> <item msgid="5908720590832378783">"Уключана"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 77542de3bec9..339d751b1594 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"премахване на избора от приспособлението"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Намаляване на височината"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Увеличаване на височината"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Показване на следващия"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Показване на предишния"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Приспособления за заключения екран"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"За да отворите дадено приложение посредством приспособление, ще трябва да потвърдите, че това сте вие. Също така имайте предвид, че всеки ще вижда приспособленията дори когато таблетът ви е заключен. Възможно е някои от тях да не са предназначени за заключения екран и добавянето им на него може да е опасно."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Разбрах"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа функциите за разговор"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Отзиви"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Отхвърляне"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Да не се показва отново"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Известията за обаждания не могат да бъдат променяни."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Тази група от известия не може да бъде конфигурирана тук"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Разгъване на сгъваемо устройство"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Обръщане на сгъваемо устройство"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Предният екран е включен"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Плъзнете, за да използвате вътрешния екран"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворено"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворено"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-bg/tiles_states_strings.xml b/packages/SystemUI/res/values-bg/tiles_states_strings.xml index cc632db72abf..e598f928aad1 100644 --- a/packages/SystemUI/res/values-bg/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-bg/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Изкл."</item> <item msgid="5908720590832378783">"Вкл."</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 6bd1e0c0fc71..ef1253b55de0 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"উইজেট বাদ দিন"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"উচ্চতা কমান"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"উচ্চতা বাড়ান"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"পরেরটি দেখুন"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"আগেরটি দেখুন"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"লক স্ক্রিন উইজেট"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"উইজেট ব্যবহার করে কোনও অ্যাপ খুলতে, আপনাকে নিজের পরিচয় যাচাই করতে হবে। এছাড়াও, মনে রাখবেন, আপনার ট্যাবলেট লক থাকলেও যেকেউ তা দেখতে পারবেন। কিছু উইজেট আপনার লক স্ক্রিনের উদ্দেশ্যে তৈরি করা হয়নি এবং এখানে যোগ করা নিরাপদ নাও হতে পারে।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"বুঝেছি"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এ কথোপকথন ফিচার কাজ করে না"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"মতামত"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"বাতিল করুন"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"আর দেখতে চাই না"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"কল বিজ্ঞপ্তি পরিবর্তন করা যাবে না।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"এই সমস্ত বিজ্ঞপ্তিকে এখানে কনফিগার করা যাবে না"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ফোল্ড করা যায় এমন ডিভাইস খোলা হচ্ছে"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ফোল্ড করা যায় এমন ডিভাইস উল্টানো হচ্ছে"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ফ্রন্ট স্ক্রিন চালু আছে"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"ভেতরের স্ক্রিন ব্যবহার করতে স্লাইড করুন"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ফোল্ড করা রয়েছে"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ফোল্ড করা নেই"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-bn/tiles_states_strings.xml b/packages/SystemUI/res/values-bn/tiles_states_strings.xml index e21392857e7a..38d9ee72e56d 100644 --- a/packages/SystemUI/res/values-bn/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-bn/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"বন্ধ আছে"</item> <item msgid="5908720590832378783">"চালু আছে"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 4ccc38ad8572..aa036d453428 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"poništavanje odabira vidžeta"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Smanjenje visine"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Povećanje visine"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Prikaz sljedećeg"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Prikaz prethodnog"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Vidžeti na zaključanom ekranu"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da otvorite aplikaciju pomoću vidžeta, morat ćete potvrditi identitet. Također imajte na umu da ih svako može pregledati, čak i ako je tablet zaključan. Neki vidžeti možda nisu namijenjeni za vaš zaključani ekran i njihovo dodavanje ovdje možda nije sigurno."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Razumijem"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava funkcije razgovora"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Povratne informacije"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Odbaci"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne prikazuj ponovo"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Nije moguće izmijeniti obavještenja o pozivima."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ovu grupu obavještenja nije moguće konfigurirati ovdje"</string> @@ -1394,7 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Sklopivi uređaj se rasklapa"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Sklopivi uređaj se obrće"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Prednji ekran je uključen"</string> - <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Kliznite za upotrebu unutarnjeg zaslona"</string> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Kliznite da koristite unutrašnji ekran"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"sklopljeno"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"otklopljeno"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-bs/tiles_states_strings.xml b/packages/SystemUI/res/values-bs/tiles_states_strings.xml index 2401e4a2fc37..3b9901937dd3 100644 --- a/packages/SystemUI/res/values-bs/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-bs/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Isključeno"</item> <item msgid="5908720590832378783">"Uključeno"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 80558a92194c..15d928308e69 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"desselecciona el widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Redueix l\'alçada"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Augmenta l\'alçada"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Mostra el següent"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Mostra l\'anterior"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets de la pantalla de bloqueig"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Per obrir una aplicació utilitzant un widget, necessitaràs verificar la teva identitat. També has de tenir en compte que qualsevol persona pot veure els widgets, fins i tot quan la tauleta està bloquejada. És possible que alguns widgets no estiguin pensats per a la pantalla de bloqueig i que no sigui segur afegir-los-hi."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entesos"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet les funcions de converses"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Suggeriments"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Ignora"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"No ho tornis a mostrar"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Les notificacions de trucades no es poden modificar."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquest grup de notificacions no es pot configurar aquí"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositiu plegable desplegant-se"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositiu plegable girant"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"La pantalla frontal està activada"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Llisca per utilitzar la pantalla interior"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegat"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegat"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> @@ -1474,7 +1480,7 @@ <string name="shortcut_helper_key_combinations_forward_slash" msgid="1238652537199346970">"barra inclinada"</string> <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Ansa per arrossegar"</string> <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Configuració del teclat"</string> - <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Configura la drecera"</string> + <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Configura"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Suprimeix"</string> <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sí, restableix"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel·la"</string> diff --git a/packages/SystemUI/res/values-ca/tiles_states_strings.xml b/packages/SystemUI/res/values-ca/tiles_states_strings.xml index 94d554562b1c..e0c3fb9c7c73 100644 --- a/packages/SystemUI/res/values-ca/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ca/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Desactivat"</item> <item msgid="5908720590832378783">"Activat"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index ee321074a250..031e59d03bb0 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"zrušit výběr widgetu"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Snížit výšku"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Zvýšit výšku"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Zobrazit další"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Zobrazit předchozí"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgety na obrazovce uzamčení"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"K otevření aplikace pomocí widgetu budete muset ověřit svou totožnost. Také mějte na paměti, že widgety uvidí kdokoli, i když tablet bude uzamčen. Některé widgety nemusí být pro obrazovku uzamčení určeny a nemusí být bezpečné je na ni přidat."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Rozumím"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> funkce konverzace nepodporuje"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Zpětná vazba"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Zavřít"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Už nezobrazovat"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Upozornění na hovor nelze upravit."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tuto skupinu oznámení tady nelze nakonfigurovat"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Rozkládání rozkládacího zařízení"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Otáčení rozkládacího zařízení"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Přední obrazovka je zapnutá"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Pokud chcete použít vnitřní obrazovku, přejeďte prstem"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"složené"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"rozložené"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-cs/tiles_states_strings.xml b/packages/SystemUI/res/values-cs/tiles_states_strings.xml index a02ed764ab0e..ea62773166f3 100644 --- a/packages/SystemUI/res/values-cs/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-cs/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Vypnuto"</item> <item msgid="5908720590832378783">"Zapnuto"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 323b9d884ad5..1ddaf8c84cdf 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"fjern markering af widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Reducer højden"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Forøg højden"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Vis næste"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Vis forrige"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets på låseskærmen"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Hvis du vil åbne en app ved hjælp af en widget, skal du verificere din identitet. Husk også, at alle kan se dem, også når din tablet er låst. Nogle widgets er muligvis ikke beregnet til låseskærmen, og det kan være usikkert at tilføje dem her."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalefunktioner"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Luk"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Vis ikke igen"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Opkaldsnotifikationer kan ikke redigeres."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Du kan ikke konfigurere denne gruppe notifikationer her"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldbar enhed foldes ud"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldbar enhed vendes om"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontskærmen er aktiveret"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Skub for at bruge den indre skærm"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"foldet"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"foldet ud"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-da/tiles_states_strings.xml b/packages/SystemUI/res/values-da/tiles_states_strings.xml index 8b536a286af0..2b1dbcfe0d73 100644 --- a/packages/SystemUI/res/values-da/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-da/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Fra"</item> <item msgid="5908720590832378783">"Til"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 3c8be75f894b..16bbea1c4df2 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -463,7 +463,7 @@ <string name="zen_mode_off" msgid="1736604456618147306">"Aus"</string> <string name="zen_mode_set_up" msgid="8231201163894922821">"Nicht festgelegt"</string> <string name="zen_mode_no_manual_invocation" msgid="1769975741344633672">"In den Einstellungen verwalten"</string> - <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Keine aktiven Modi}=1{{mode} aktiv}other{# aktiv}}"</string> + <string name="zen_mode_active_modes" msgid="1625850411578488856">"{count,plural, =0{Kein Modus aktiv}=1{{mode} aktiv}other{# aktiv}}"</string> <string name="zen_priority_introduction" msgid="3159291973383796646">"Klingeltöne und die Vibration werden deaktiviert, außer für Weckrufe, Erinnerungen, Termine sowie Anrufe von zuvor von dir festgelegten Personen. Du hörst jedoch weiterhin Sound, wenn du dir Musik anhörst, Videos ansiehst oder Spiele spielst."</string> <string name="zen_alarms_introduction" msgid="3987266042682300470">"Klingeltöne und die Vibration werden deaktiviert, außer für Weckrufe. Du hörst jedoch weiterhin Sound, wenn du dir Musik anhörst, Videos ansiehst oder Spiele spielst."</string> <string name="zen_priority_customize_button" msgid="4119213187257195047">"Anpassen"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"Auswahl für Widget aufheben"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Höhe verringern"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Höhe vergrößern"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Nächstes Element anzeigen"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Vorheriges Element anzeigen"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Sperrbildschirm-Widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Wenn du eine App mit einem Widget öffnen möchtest, musst du deine Identität bestätigen. Beachte auch, dass jeder die Widgets sehen kann, auch wenn dein Tablet gesperrt ist. Einige Widgets sind möglicherweise nicht für den Sperrbildschirm vorgesehen, sodass es unsicher sein kann, sie hier hinzuzufügen."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ok"</string> @@ -541,7 +543,7 @@ <string name="hub_onboarding_bottom_sheet_title" msgid="162092881395529947">"Hub-Modus entdecken"</string> <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Du kannst während des Ladevorgangs auf deine bevorzugten Widgets und Bildschirmschoner zugreifen."</string> <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Los gehts"</string> - <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Beim Laden deine bevorzugten Bildschirmschoner anzeigen"</string> + <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Beim Laden werden deine Lieblings-Bildschirmschoner angezeigt"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine Funktionen für Unterhaltungen"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Schließen"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Nicht mehr anzeigen"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Anrufbenachrichtigungen können nicht geändert werden."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Die Benachrichtigungsgruppe kann hier nicht konfiguriert werden"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Faltbares Gerät wird geöffnet"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Faltbares Gerät wird umgeklappt"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontdisplay aktiviert"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Ziehen, um das innere Display zu verwenden"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"zugeklappt"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"aufgeklappt"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-de/tiles_states_strings.xml b/packages/SystemUI/res/values-de/tiles_states_strings.xml index bb39b4e3c2b3..ded7efd39cf0 100644 --- a/packages/SystemUI/res/values-de/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-de/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Aus"</item> <item msgid="5908720590832378783">"An"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 470dd2c1f353..89c2cd2db876 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"αποεπιλογή γραφικού στοιχείου"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Μείωση του ύψους"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Αύξηση του ύψους"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Εμφάνιση επόμενου"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Εμφάνιση προηγούμενου"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Γραφικά στοιχεία οθόνης κλειδώματος"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Για να ανοίξετε μια εφαρμογή χρησιμοποιώντας ένα γραφικό στοιχείο, θα πρέπει να επαληθεύσετε την ταυτότητά σας. Επίσης, λάβετε υπόψη ότι η προβολή τους είναι δυνατή από οποιονδήποτε, ακόμα και όταν το tablet σας είναι κλειδωμένο. Ορισμένα γραφικά στοιχεία μπορεί να μην προορίζονται για την οθόνη κλειδώματος και η προσθήκη τους εδώ ενδέχεται να μην είναι ασφαλής."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Το κατάλαβα"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει τις λειτουργίες συζήτησης"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Σχόλια"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Παράβλεψη"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Να μην εμφανιστεί ξανά"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Δεν είναι δυνατή η τροποποίηση των ειδοποιήσεων κλήσεων."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Δεν είναι δυνατή η διαμόρφωση αυτής της ομάδας ειδοποιήσεων εδώ"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Αναδιπλούμενη συσκευή που ξεδιπλώνει"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Αναδιπλούμενη συσκευή που διπλώνει"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Η μπροστινή οθόνη ενεργοποιήθηκε"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Σύρετε για χρήση της εσωτερικής οθόνης"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"διπλωμένη"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ξεδιπλωμένη"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-el/tiles_states_strings.xml b/packages/SystemUI/res/values-el/tiles_states_strings.xml index 5ce4b8c820fb..398bf13563fb 100644 --- a/packages/SystemUI/res/values-el/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-el/tiles_states_strings.xml @@ -64,7 +64,7 @@ <string-array name="tile_states_rotation"> <item msgid="4578491772376121579">"Μη διαθέσιμο"</item> <item msgid="5776427577477729185">"Ανενεργό"</item> - <item msgid="7105052717007227415">"Ενεργό"</item> + <item msgid="7105052717007227415">"Ενεργή"</item> </string-array> <string-array name="tile_states_bt"> <item msgid="5330252067413512277">"Μη διαθέσιμο"</item> @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Ανενεργό"</item> <item msgid="5908720590832378783">"Ενεργό"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 0c161a7493f5..af0703cfcfd3 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"unselect widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Decrease height"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Increase height"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Show next"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Show previous"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Slide to use inner screen"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml index 1b60921d3237..d62f2e514fbb 100644 --- a/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-en-rAU/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Off"</item> <item msgid="5908720590832378783">"On"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 3a7440bceaa0..f171a78618e8 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"unselect widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Decrease height"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Increase height"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Show next"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Show previous"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you’ll need to verify it’s you. Also, keep in mind that anyone can view them, even when your tablet’s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string> @@ -806,7 +808,9 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string> + <string name="notification_inline_disable_promotion" msgid="3551682588314376921">"Don\'t show as pinned"</string> + <string name="live_notifications_title" msgid="1586553354601345379">"Showing Live Updates"</string> + <string name="live_notifications_desc" msgid="7470787001768372152">"Pinned notifications display live info from apps, and always appear on the status bar and lock screen"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> diff --git a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml index 1b60921d3237..d62f2e514fbb 100644 --- a/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-en-rCA/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Off"</item> <item msgid="5908720590832378783">"On"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 0c161a7493f5..af0703cfcfd3 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"unselect widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Decrease height"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Increase height"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Show next"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Show previous"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Slide to use inner screen"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml index 1b60921d3237..d62f2e514fbb 100644 --- a/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-en-rGB/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Off"</item> <item msgid="5908720590832378783">"On"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 0c161a7493f5..af0703cfcfd3 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"unselect widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Decrease height"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Increase height"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Show next"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Show previous"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lock screen widgets"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"To open an app using a widget, you\'ll need to verify that it\'s you. Also, bear in mind that anyone can view them, even when your tablet\'s locked. Some widgets may not have been intended for your lock screen and may be unsafe to add here."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Got it"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> doesn’t support conversation features"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Dismiss"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Don\'t show again"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Call notifications can\'t be modified."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"This group of notifications cannot be configured here"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Foldable device being unfolded"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Foldable device being flipped around"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Front screen turned on"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Slide to use inner screen"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"folded"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"unfolded"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml index 1b60921d3237..d62f2e514fbb 100644 --- a/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-en-rIN/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Off"</item> <item msgid="5908720590832378783">"On"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index dd8f735197b8..0e15e4527313 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"anular la selección del widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Reducir la altura"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumentar la altura"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Mostrar siguiente"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Mostrar anterior"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets en la pantalla de bloqueo"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir una app usando un widget, debes verificar tu identidad. Además, ten en cuenta que cualquier persona podrá verlo, incluso cuando la tablet esté bloqueada. Es posible que algunos widgets no se hayan diseñados para la pantalla de bloqueo y podría ser peligroso agregarlos allí."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Comentarios"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Descartar"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"No volver a mostrar"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"No se pueden modificar las notificaciones de llamada."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"No se puede configurar aquí este grupo de notificaciones"</string> diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml index 1c587d663563..d8354833f91b 100644 --- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Desactivado"</item> <item msgid="5908720590832378783">"Activado"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index a2fcc5c75e1e..1670ce6737b8 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"deseleccionar widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Reducir altura"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumentar altura"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Mostrar siguiente"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Mostrar anterior"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets para la pantalla de bloqueo"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir una aplicación usando un widget, deberás verificar que eres tú. Además, ten en cuenta que cualquier persona podrá verlos, incluso aunque tu tablet esté bloqueada. Es posible que algunos widgets no estén pensados para la pantalla de bloqueo y no sea seguro añadirlos aquí."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite funciones de conversación"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Comentarios"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Cerrar"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"No volver a mostrar"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Las notificaciones de llamada no se pueden modificar."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Este grupo de notificaciones no se puede configurar aquí"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo plegable desplegándose"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo plegable mostrado desde varios ángulos"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Pantalla frontal encendida"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Desliza para usar la pantalla interior"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plegado"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"desplegado"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml index 5c4f36a064db..ea75e5296ca9 100644 --- a/packages/SystemUI/res/values-es/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Desactivado"</item> <item msgid="5908720590832378783">"Activado"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index bca749190858..445b540ae3eb 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -504,8 +504,8 @@ <string name="accessibility_action_open_communal_hub" msgid="3081702792413787849">"Lukustuskuva vidinad"</string> <string name="accessibility_announcement_communal_widget_added" msgid="6911593106099328271">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g> lisati lukustuskuvale"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Ühise õpetuse käivitamiseks pühkige vasakule"</string> - <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"Kohandage"</string> - <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"Loobuge"</string> + <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"Kohanda"</string> + <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"Loobu"</string> <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Lisage ja eemaldage vidinaid ning muutke nende järjestust"</string> <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisage rohkem vidinaid"</string> <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vajutage pikalt vidinate kohandamiseks"</string> @@ -530,10 +530,12 @@ <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"eemaldage vidin"</string> <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"asetage valitud vidin"</string> <string name="communal_widget_picker_title" msgid="1953369090475731663">"Lukustuskuva vidinad"</string> - <string name="communal_widget_picker_description" msgid="490515450110487871">"Igaüks saab vaadata luk.kuval olevaid vidinaid, isegi kui tahvelarvuti on lukus."</string> + <string name="communal_widget_picker_description" msgid="490515450110487871">"Igaüks saab vaadata lukustuskuval olevaid vidinaid, isegi kui tahvelarvuti on lukus."</string> <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"tühistage vidina valimine"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Vähenda kõrgust"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Suurenda kõrgust"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Kuva järgmine"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Kuva eelmine"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lukustuskuva vidinad"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Rakenduse avamiseks vidina abil peate kinnitama, et see olete teie. Samuti pidage meeles, et kõik saavad vidinaid vaadata, isegi kui teie tahvelarvuti on lukus. Mõni vidin ei pruugi olla ette nähtud teie lukustuskuva jaoks ja seda pole turvaline siia lisada."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Selge"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestlusfunktsioone"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Tagasiside"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Loobu"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ära enam näita"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Kõnemärguandeid ei saa muuta."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Seda märguannete rühma ei saa siin seadistada"</string> diff --git a/packages/SystemUI/res/values-et/tiles_states_strings.xml b/packages/SystemUI/res/values-et/tiles_states_strings.xml index f9951280e5d4..a9f0880c3628 100644 --- a/packages/SystemUI/res/values-et/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-et/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Väljas"</item> <item msgid="5908720590832378783">"Sees"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index f447dc6e6c48..1f7d697ff2da 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"desautatu widgeta"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Txikitu altuera"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Handitu altuera"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Erakutsi hurrengoa"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Erakutsi aurrekoa"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Pantaila blokeatuko widgetak"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Aplikazio bat widget baten bidez irekitzeko, zeu zarela egiaztatu beharko duzu. Gainera, kontuan izan edonork ikusi ahalko dituela halako widgetak, tableta blokeatuta badago ere. Baliteke widget batzuk pantaila blokeaturako egokiak ez izatea, eta agian ez da segurua haiek bertan gehitzea."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ados"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez ditu onartzen elkarrizketetarako eginbideak"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Iritzia"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Baztertu"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ez erakutsi berriro"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Deien jakinarazpenak ezin dira aldatu."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Jakinarazpen talde hau ezin da konfiguratu hemen"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Gailu tolesgarria zabaltzen"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Gailu tolesgarria biratzen"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Aurreko pantaila piztuta dago"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Lerratu hau barneko pantaila erabiltzeko"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"tolestuta"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"tolestu gabe"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-eu/tiles_states_strings.xml b/packages/SystemUI/res/values-eu/tiles_states_strings.xml index 5d4672f55adc..62bbc27010a9 100644 --- a/packages/SystemUI/res/values-eu/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-eu/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Desaktibatuta"</item> <item msgid="5908720590832378783">"Aktibatuta"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 800bf785c339..c9392e32d6c1 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -125,7 +125,7 @@ <string name="screenrecord_continue" msgid="4055347133700593164">"شروع"</string> <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"درحال ضبط صفحهنمایش"</string> <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"درحال ضبط صفحهنمایش و صدا"</string> - <string name="screenrecord_taps_label" msgid="1595690528298857649">"نمایش قسمتهای لمسشده روی صفحهنمایش"</string> + <string name="screenrecord_taps_label" msgid="1595690528298857649">"نمایش نقاط لمس روی صفحهنمایش"</string> <string name="screenrecord_stop_label" msgid="72699670052087989">"متوقف کردن"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"همرسانی"</string> <string name="screenrecord_save_title" msgid="1886652605520893850">"قطعه ضبطشده از صفحهنمایش ذخیره شد"</string> @@ -133,7 +133,7 @@ <string name="screenrecord_save_error" msgid="5862648532560118815">"خطا در ذخیرهسازی ضبط صفحهنمایش"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"خطا هنگام شروع ضبط صفحهنمایش"</string> <string name="screenrecord_stop_dialog_title" msgid="8716193661764511095">"ضبط متوقف شود؟"</string> - <string name="screenrecord_stop_dialog_message" msgid="6262768207331626817">"اکنون درحال ضبط کل صفحهنمایشتان هستید"</string> + <string name="screenrecord_stop_dialog_message" msgid="6262768207331626817">"اکنون درحال ضبط کل صفحهنمایش هستید"</string> <string name="screenrecord_stop_dialog_message_specific_app" msgid="5995770227684523244">"اکنون درحال ضبط <xliff:g id="APP_NAME">%1$s</xliff:g> هستید"</string> <string name="screenrecord_stop_dialog_button" msgid="2883812564938194350">"توقف ضبط"</string> <string name="share_to_app_chip_accessibility_label" msgid="4210256229976947065">"درحال همرسانی صفحه"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"لغو انتخاب ابزاره"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"کاهش ارتفاع"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"افزایش ارتفاع"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"نمایش بعدی"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"نمایش قبلی"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ابزارههای صفحه قفل"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"برای باز کردن برنامه بااستفاده از ابزاره، باید هویت خودتان را بهتأیید برسانید. همچنین، بهخاطر داشته باشید که همه میتوانند آنها را مشاهده کنند، حتی وقتی رایانه لوحیتان قفل است. برخیاز ابزارهها ممکن است برای صفحه قفل درنظر گرفته نشده باشند و ممکن است اضافه کردن آنها در اینجا ناامن باشد."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"متوجهم"</string> @@ -542,7 +544,7 @@ <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"در حین شارژ، به ابزارهها و محافظهای صفحهنمایش دلخواهتان دسترسی داشته باشید."</string> <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"بیایید شروع کنیم"</string> <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"نمایش محافظهای صفحهنمایش دلخواه درحین شارژ"</string> - <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string> + <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تعویض کاربر"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"منوی پایینپر"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامهها و دادههای این جلسه حذف خواهد شد."</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد میگوییم!"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ویژگیهای مکالمه پشتیبانی نمیکند"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"بازخورد"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"بستن"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"دیگر نشان داده نشود"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"این اعلانها قابل اصلاح نیستند."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"این اعلانها قابلاصلاح نیستند."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"نمیتوانید این گروه اعلانها را در اینجا پیکربندی کنید"</string> diff --git a/packages/SystemUI/res/values-fa/tiles_states_strings.xml b/packages/SystemUI/res/values-fa/tiles_states_strings.xml index 1f9d6c6218f7..edc2d412405a 100644 --- a/packages/SystemUI/res/values-fa/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fa/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"خاموش"</item> <item msgid="5908720590832378783">"روشن"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index fdf18a3c77e2..96162b211006 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -536,6 +536,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"poista widgetin valinta"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Vähennä korkeutta"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Lisää korkeutta"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Näytä seuraava"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Näytä edellinen"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Lukitusnäytön widgetit"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Jos haluat avata sovelluksen käyttämällä widgetiä, sinun täytyy vahvistaa henkilöllisyytesi. Muista myös, että widgetit näkyvät kaikille, vaikka tabletti olisi lukittuna. Jotkin widgetit on ehkä tarkoitettu lukitusnäytölle, ja niiden lisääminen tänne ei välttämättä ole turvallista."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Selvä"</string> @@ -808,7 +810,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskusteluominaisuuksia"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Palaute"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Hylkää"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Älä näytä uudelleen"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Puheluilmoituksia ei voi muokata."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tätä ilmoitusryhmää ei voi määrittää tässä"</string> @@ -1396,8 +1403,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Taitettava laite taitetaan"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Taitettava laite käännetään ympäri"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Etunäyttö päällä"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Liu\'uta käyttääksesi sisäistä näyttöä"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"taitettu"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"taittamaton"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-fi/tiles_states_strings.xml b/packages/SystemUI/res/values-fi/tiles_states_strings.xml index 96750ef02d01..6b1a8eddec63 100644 --- a/packages/SystemUI/res/values-fi/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fi/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Pois päältä"</item> <item msgid="5908720590832378783">"Päällä"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index dde9b64f661b..8fd2ed219953 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"désélectionner le widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Diminuer la hauteur"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Augmenter la hauteur"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Afficher le suivant"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Afficher le précédent"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets de l\'écran de verrouillage"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pour ouvrir une appli à l\'aide d\'un widget, vous devrez confirmer votre identité. En outre, gardez à l\'esprit que tout le monde peut voir les widgets, même lorsque votre tablette est verrouillée. Certains widgets n\'ont peut-être pas été conçus pour votre écran de verrouillage, et il pourrait être dangereux de les ajouter ici."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les fonctionnalités de conversation"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Commentaires"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Fermer"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne plus afficher"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Les notifications d\'appel ne peuvent pas être modifiées."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ce groupe de notifications ne peut pas être configuré ici"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable en cours de dépliage"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable en train d\'être retourné"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Écran avant activé"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Faites glisser pour utiliser l\'écran intérieur"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml index ffacde22416a..4734d860e27a 100644 --- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Désactivée"</item> <item msgid="5908720590832378783">"Activée"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 53dbfea51363..89002d4752b4 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"désélectionner le widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Diminuer la hauteur"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Augmenter la hauteur"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Afficher le suivant"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Afficher le précédent"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets pour l\'écran de verrouillage"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pour ouvrir une appli à l\'aide d\'un widget, vous devez confirmer qu\'il s\'agit bien de vous. N\'oubliez pas non plus que tout le monde peut voir vos widgets, même lorsque votre tablette est verrouillée. Certains d\'entre eux n\'ont pas été conçus pour l\'écran de verrouillage et les ajouter à cet endroit peut s\'avérer dangereux."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les fonctionnalités de conversation"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Commentaires"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Ignorer"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne plus afficher"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Impossible de modifier les notifications d\'appel."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Vous ne pouvez pas configurer ce groupe de notifications ici"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Appareil pliable qui est déplié"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Appareil pliable qui est retourné"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Écran avant activé"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Faites glisser pour utiliser l\'écran intérieur"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"plié"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"déplié"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-fr/tiles_states_strings.xml b/packages/SystemUI/res/values-fr/tiles_states_strings.xml index ffceb0dfe776..cefc9a2af3ed 100644 --- a/packages/SystemUI/res/values-fr/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-fr/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Désactivé"</item> <item msgid="5908720590832378783">"Activé"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 03ec2b0ad817..4e801eebf317 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -125,7 +125,7 @@ <string name="screenrecord_continue" msgid="4055347133700593164">"Iniciar"</string> <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Gravando pantalla"</string> <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Gravando pantalla e audio"</string> - <string name="screenrecord_taps_label" msgid="1595690528298857649">"Mostrar a localización dos toques na pantalla"</string> + <string name="screenrecord_taps_label" msgid="1595690528298857649">"Mostrar localización dos toques na pantalla"</string> <string name="screenrecord_stop_label" msgid="72699670052087989">"Deter"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Compartir"</string> <string name="screenrecord_save_title" msgid="1886652605520893850">"Gravación da pantalla gardada"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"anular a selección do widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Reducir a altura"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumentar a altura"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Mostrar seguinte"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Mostrar anterior"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da pantalla de bloqueo"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir unha aplicación mediante un widget, tes que verificar a túa identidade. Ten en conta que pode velos calquera persoa, mesmo coa tableta bloqueada. Pode ser que algúns widgets non estean pensados para a túa pantalla de bloqueo, polo que talvez non sexa seguro engadilos aquí."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendido"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite funcións de conversa"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Comentarios"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Pechar"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Non volver mostrar"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"As notificacións de chamadas non se poden modificar."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Aquí non se pode configurar este grupo de notificacións"</string> @@ -1349,7 +1356,7 @@ <string name="clipboard_image_preview" msgid="2156475174343538128">"Vista previa da imaxe"</string> <string name="clipboard_edit" msgid="4500155216174011640">"editar"</string> <string name="add" msgid="81036585205287996">"Engadir"</string> - <string name="manage_users" msgid="1823875311934643849">"Usuarios"</string> + <string name="manage_users" msgid="1823875311934643849">"Xestionar usuarios"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Esta notificación non pode arrastrarse á pantalla dividida"</string> <string name="dream_overlay_location_active" msgid="6484763493158166618">"Localización activa"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"A wifi non está dispoñible"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispositivo pregable abríndose"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispositivo pregable xirando"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Activouse a pantalla dianteira"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Pasa o dedo para usar a pantalla interior"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"dispositivo pregado"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dispositivo despregado"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-gl/tiles_states_strings.xml b/packages/SystemUI/res/values-gl/tiles_states_strings.xml index 7889983f193b..bfd6a121da73 100644 --- a/packages/SystemUI/res/values-gl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-gl/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Opción desactivada"</item> <item msgid="5908720590832378783">"Opción activada"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 0c27927e2662..08e139872a50 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"વિજેટ નાપસંદ કરો"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ઊંચાઈ ઘટાડો"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ઊંચાઈ વધારો"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"આગલું બતાવો"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"પાછલું બતાવો"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"લૉક સ્ક્રીન વિજેટ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"વિજેટનો ઉપયોગ કરીને ઍપ ખોલવા માટે, તમારે એ ચકાસણી કરવાની જરૂર રહેશે કે આ તમે જ છો. તે ઉપરાંત, ધ્યાનમાં રાખો કે તમારું ટૅબ્લેટ લૉક કરેલું હોય તો પણ કોઈપણ વ્યક્તિ તેમને જોઈ શકે છે. અમુક વિજેટ કદાચ તમારી લૉક સ્ક્રીન માટે બનાવવામાં આવ્યા ન હોઈ શકે છે અને તેમને અહીં ઉમેરવાનું અસલામત હોઈ શકે છે."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"સમજાઈ ગયું"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીતની સુવિધાઓને સપોર્ટ આપતી નથી"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"પ્રતિસાદ"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"છોડી દો"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ફરી બતાવશો નહીં"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"કૉલના નોટિફિકેશનમાં કોઈ ફેરફાર કરી શકાતો નથી."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"નોટિફિકેશનના આ ગ્રૂપની ગોઠવણી અહીં કરી શકાશે નહીં"</string> diff --git a/packages/SystemUI/res/values-gu/tiles_states_strings.xml b/packages/SystemUI/res/values-gu/tiles_states_strings.xml index 17b47cc201d0..c6e204d12745 100644 --- a/packages/SystemUI/res/values-gu/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-gu/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"બંધ છે"</item> <item msgid="5908720590832378783">"ચાલુ"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index f2daffe3f443..d78158557756 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"विजेट से चुने हुए का निशान हटाएं"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ऊंचाई घटाएं"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ऊंचाई बढ़ाएं"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"अगला दिखाएं"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"पिछला दिखाएं"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लॉक स्क्रीन विजेट"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"किसी विजेट से कोई ऐप्लिकेशन खोलने के लिए, आपको अपनी पहचान की पुष्टि करनी होगी. ध्यान रखें कि आपके टैबलेट के लॉक होने पर भी, कोई व्यक्ति विजेट देख सकता है. ऐसा हो सकता है कि कुछ विजेट, लॉक स्क्रीन पर दिखाने के लिए न बने हों. इन्हें लॉक स्क्रीन पर जोड़ना असुरक्षित हो सकता है."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ठीक है"</string> @@ -542,7 +544,7 @@ <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"चार्जिंग के दौरान, अपने पसंदीदा विजेट और स्क्रीन सेवर को ऐक्सेस करें."</string> <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"आइए शुरू करें"</string> <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"चार्ज करते समय अपने पसंदीदा स्क्रीन सेवर दिखाएं"</string> - <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string> + <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"दूसरे खाते पर स्विच करें"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेन्यू"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सेशन के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"मेहमान, आपका फिर से स्वागत है!"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर बातचीत की सुविधाएं काम नहीं करतीं"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"सुझाव/राय दें या शिकायत करें"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"खारिज करें"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"फिर से न दिखाएं"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कॉल से जुड़ी सूचनाओं को ब्लॉक नहीं किया जा सकता."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"सूचनाओं के इस समूह को यहां कॉन्फ़िगर नहीं किया जा सकता"</string> diff --git a/packages/SystemUI/res/values-hi/tiles_states_strings.xml b/packages/SystemUI/res/values-hi/tiles_states_strings.xml index 69a4e4daa355..65046cc4216d 100644 --- a/packages/SystemUI/res/values-hi/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-hi/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"बंद है"</item> <item msgid="5908720590832378783">"चालू है"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 5222e8010e81..3a985a9f5a17 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"poništavanje odabira widgeta"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Smanjenje visine"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Povećanje visine"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Prikazivanje sljedećeg"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Prikazivanje prethodnog"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgeti na zaključanom zaslonu"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Da biste otvorili aplikaciju pomoću widgeta, trebate potvrditi da ste to vi. Također napominjemo da ih svatko može vidjeti, čak i ako je vaš tablet zaključan. Neki widgeti možda nisu namijenjeni za zaključani zaslon, pa ih možda nije sigurno dodati ovdje."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Shvaćam"</string> @@ -731,7 +733,7 @@ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"isključen zvuk"</string> <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibriranje"</string> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> se reproducira na"</string> - <string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk će se reproducirati na"</string> + <string name="media_output_title_without_playing" msgid="3825663683169305013">"Za reprodukciju zvuka koristi se"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Pozivanje na uređaju"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Ugađanje korisničkog sučelja sustava"</string> <string name="status_bar" msgid="4357390266055077437">"Traka statusa"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava značajke razgovora"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Povratne informacije"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Odbaci"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne prikazuj ponovo"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obavijesti o pozivima ne mogu se izmijeniti."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ta se grupa obavijesti ne može konfigurirati ovdje"</string> diff --git a/packages/SystemUI/res/values-hr/tiles_states_strings.xml b/packages/SystemUI/res/values-hr/tiles_states_strings.xml index 2401e4a2fc37..3b9901937dd3 100644 --- a/packages/SystemUI/res/values-hr/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-hr/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Isključeno"</item> <item msgid="5908720590832378783">"Uključeno"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 109c52fd6e8d..9b1756703895 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"modul kijelölésének megszüntetése"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Magasság csökkentése"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Magasság növelése"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Következő mutatása"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Előző mutatása"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"A lezárási képernyő moduljai"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ha modul használatával szeretne megnyitni egy alkalmazást, igazolnia kell a személyazonosságát. Ne felejtse továbbá, hogy bárki megtekintheti a modulokat, még akkor is, amikor zárolva van a táblagép. Előfordulhat, hogy bizonyos modulokat nem a lezárási képernyőn való használatra terveztek, ezért nem biztonságos a hozzáadásuk."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Értem"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> nem támogatja a beszélgetési funkciókat"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Visszajelzés"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Elvetés"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ne jelenjen meg újra"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"A hívásértesítéseket nem lehet módosítani."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Az értesítések jelen csoportját itt nem lehet beállítani"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Összehajtható eszköz kihajtása"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Összehajtható eszköz körbeforgatása"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Előlapi képernyő bekapcsolva"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Csúsztatás a belső képernyő használatához"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"összehajtva"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kihajtva"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-hu/tiles_states_strings.xml b/packages/SystemUI/res/values-hu/tiles_states_strings.xml index 8911fe9e2f8d..06bf4f26ab84 100644 --- a/packages/SystemUI/res/values-hu/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-hu/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Ki"</item> <item msgid="5908720590832378783">"Be"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 914d2cd8fd78..2aa72cc66e8a 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"չեղարկել վիջեթի ընտրությունը"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Նվազեցնել բարձրությունը"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Ավելացնել բարձրությունը"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Ցույց տալ հաջորդը"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Ցույց տալ նախորդը"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Կողպէկրանի վիջեթներ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Վիջեթի միջոցով հավելված բացելու համար դուք պետք է հաստատեք ձեր ինքնությունը։ Նաև նկատի ունեցեք, որ ցանկացած ոք կարող է դիտել վիջեթները, նույնիսկ երբ ձեր պլանշետը կողպված է։ Որոշ վիջեթներ կարող են նախատեսված չլինել ձեր կողպէկրանի համար, և այստեղ դրանց ավելացնելը կարող է վտանգավոր լինել։"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Եղավ"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը զրույցի գործառույթներ չի աջակցում"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Կարծիք հայտնել"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Փակել"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Այլևս ցույց չտալ"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Զանգերի մասին ծանուցումները հնարավոր չէ փոփոխել։"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ծանուցումների տվյալ խումբը հնարավոր չէ կարգավորել այստեղ"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ծալովի սարք՝ բացված վիճակում"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Ծալովի սարք՝ շրջված վիճակում"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Առջևի էկրանը միացված է"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Սահեցրեք՝ ներքին էկրանն օգտագործելու համար"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ծալված"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"բացված"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-hy/tiles_states_strings.xml b/packages/SystemUI/res/values-hy/tiles_states_strings.xml index f2b09e059429..dc8bbb14c0cf 100644 --- a/packages/SystemUI/res/values-hy/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-hy/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Անջատված է"</item> <item msgid="5908720590832378783">"Միացված է"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 62e347603242..c57f40f4b69d 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -250,8 +250,8 @@ <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Persentase baterai tidak diketahui."</string> <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Terhubung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</string> <string name="accessibility_cast_name" msgid="7344437925388773685">"Terhubung ke <xliff:g id="CAST">%s</xliff:g>."</string> - <string name="accessibility_expand_group" msgid="521237935987978624">"Meluaskan grup."</string> - <string name="accessibility_open_application" msgid="1749126077501259712">"Membuka aplikasi."</string> + <string name="accessibility_expand_group" msgid="521237935987978624">"Luaskan grup."</string> + <string name="accessibility_open_application" msgid="1749126077501259712">"Buka aplikasi."</string> <string name="accessibility_not_connected" msgid="4061305616351042142">"Tidak terhubung."</string> <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string> <string name="cell_data_off" msgid="4886198950247099526">"Nonaktif"</string> @@ -345,7 +345,7 @@ <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Jaringan tidak tersedia"</string> <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Tidak ada jaringan Wi-Fi yang tersedia"</string> <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Mengaktifkan…"</string> - <string name="quick_settings_cast_title" msgid="3033553249449938182">"Cast"</string> + <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmisikan"</string> <string name="quick_settings_casting" msgid="1435880708719268055">"Melakukan transmisi"</string> <string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Perangkat tanpa nama"</string> <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Perangkat tak tersedia"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"batalkan pilihan widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Kurangi tinggi"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Tambah tinggi"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Tampilkan berikutnya"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Tampilkan sebelumnya"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget layar kunci"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Untuk membuka aplikasi menggunakan widget, Anda perlu memverifikasi diri Anda. Selain itu, harap ingat bahwa siapa saja dapat melihatnya, bahkan saat tablet Anda terkunci. Beberapa widget mungkin tidak dirancang untuk layar kunci Anda dan mungkin tidak aman untuk ditambahkan di sini."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Oke"</string> @@ -542,7 +544,7 @@ <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Akses widget dan screensaver favorit Anda saat mengisi daya."</string> <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Mulai"</string> <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Tampilkan screensaver favorit saat mengisi daya"</string> - <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Beralih pengguna"</string> + <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ganti pengguna"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pulldown"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data dalam sesi ini akan dihapus."</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung fitur percakapan"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Masukan"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Tutup"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Jangan tampilkan lagi"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Notifikasi panggilan tidak dapat diubah."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Grup notifikasi ini tidak dapat dikonfigurasi di sini"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Perangkat foldable sedang dibentangkan"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Perangkat foldable sedang dibalik"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Layar depan diaktifkan"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Geser untuk menggunakan layar dalam"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ditutup"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"dibuka"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-in/tiles_states_strings.xml b/packages/SystemUI/res/values-in/tiles_states_strings.xml index 7462ff6a98bd..b48a5873095b 100644 --- a/packages/SystemUI/res/values-in/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-in/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Nonaktif"</item> <item msgid="5908720590832378783">"Aktif"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 4e486d01caa4..ec284c24499e 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"afturkalla val á græju"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Lækka"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Hækka"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Sýna næsta"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Sýna fyrra"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Græjur fyrir lásskjá"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Þú þarft að staðfesta að þetta sért þú til að geta opnað forrit með græju. Hafðu einnig í huga að hver sem er getur skoðað þær, jafnvel þótt spjaldtölvan sé læst. Sumar græjur eru hugsanlega ekki ætlaðar fyrir lásskjá og því gæti verið óöruggt að bæta þeim við hér."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ég skil"</string> @@ -731,7 +733,7 @@ <string name="volume_panel_hint_muted" msgid="1124844870181285320">"þaggað"</string> <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"titringur"</string> <string name="media_output_label_title" msgid="872824698593182505">"Í spilun í <xliff:g id="LABEL">%s</xliff:g>"</string> - <string name="media_output_title_without_playing" msgid="3825663683169305013">"Hljóð heldur áfram að spilast"</string> + <string name="media_output_title_without_playing" msgid="3825663683169305013">"Hljóð heldur áfram að spilast í"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Símtal í gangi"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Fínstillingar kerfisviðmóts"</string> <string name="status_bar" msgid="4357390266055077437">"Stöðustika"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki samtalseiginleika"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Ábendingar"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Loka"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ekki sýna aftur"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Ekki er hægt að breyta tilkynningum um símtöl."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ekki er hægt að stilla þessar tilkynningar hér"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Samanbrjótanlegt tæki opnað"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Samanbrjótanlegu tæki snúið við"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Kveikt á fremri skjá"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Renndu til að opna innri skjá"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"samanbrotið"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"opið"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-is/tiles_states_strings.xml b/packages/SystemUI/res/values-is/tiles_states_strings.xml index df3bcf9f1f9b..92f07b68389a 100644 --- a/packages/SystemUI/res/values-is/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-is/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Slökkt"</item> <item msgid="5908720590832378783">"Kveikt"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 786254be73c0..2391fe262ab8 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"deseleziona widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Riduci altezza"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumenta altezza"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Mostra successivo"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Mostra precedente"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget della schermata di blocco"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Per aprire un\'app utilizzando un widget, dovrai verificare la tua identità. Inoltre tieni presente che chiunque può vederlo, anche quando il tablet è bloccato. Alcuni widget potrebbero non essere stati progettati per la schermata di blocco e potrebbe non essere sicuro aggiungerli qui."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ok"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Ignora"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Non mostrare più"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Impossibile modificare gli avvisi di chiamata."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Qui non è possibile configurare questo gruppo di notifiche"</string> @@ -1396,7 +1403,7 @@ <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Schermo frontale attivato"</string> <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Scorri per usare lo schermo interno"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"Piegato"</string> - <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"Non piegato"</string> + <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"Aperto"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Batteria dello stilo: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Connetti lo stilo a un caricabatterie"</string> diff --git a/packages/SystemUI/res/values-it/tiles_states_strings.xml b/packages/SystemUI/res/values-it/tiles_states_strings.xml index 9d26859df5ed..7e11d0becfea 100644 --- a/packages/SystemUI/res/values-it/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-it/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Off"</item> <item msgid="5908720590832378783">"On"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 50008854f1df..0d7a620e7f92 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ביטול הבחירה בווידג\'ט"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"הקטנת הגובה"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"הגדלת הגובה"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"לפריט הבא"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"לפריט הקודם"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ווידג\'טים במסך הנעילה"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"כדי לפתוח אפליקציה באמצעות ווידג\'ט, עליך לאמת את זהותך. בנוסף, כדאי לזכור שכל אחד יכול לראות את הווידג\'טים גם כשהטאבלט שלך נעול. יכול להיות שחלק מהווידג\'טים לא נועדו למסך הנעילה ושלא בטוח להוסיף אותם לכאן."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"הבנתי"</string> @@ -804,10 +806,14 @@ <string name="notification_channel_summary_priority_all" msgid="7151752959650048285">"מוצגת בחלק העליון של קטע התראות השיחה וכתמונת פרופיל במסך הנעילה, מופיעה בבועה צפה ומפריעה במצב \'נא לא להפריע\'"</string> <string name="notification_priority_title" msgid="2079708866333537093">"בעדיפות גבוהה"</string> <string name="no_shortcut" msgid="8257177117568230126">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בתכונות השיחה"</string> - <!-- no translation found for notification_guts_bundle_feedback (7581587973879656500) --> - <skip /> + <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"משוב"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"סגירה"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"לא להציג את זה שוב"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"לא ניתן לשנות את התראות השיחה."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"לא ניתן להגדיר כאן את קבוצת ההתראות הזו"</string> @@ -1395,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"מכשיר מתקפל עובר למצב לא מקופל"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"מכשיר מתקפל עובר למצב מהופך"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"המסך הקדמי מופעל"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"כדי להשתמש במסך הפנימי, צריך להסיט"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"מצב מקופל"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"מצב לא מקופל"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-iw/tiles_states_strings.xml b/packages/SystemUI/res/values-iw/tiles_states_strings.xml index 1a5b8fbcd20d..2f8ec0adda5f 100644 --- a/packages/SystemUI/res/values-iw/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-iw/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"מושבת"</item> <item msgid="5908720590832378783">"מצב פעיל"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index fd98fe822b6f..786763366fd4 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ウィジェットの選択を解除する"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"高さを低くする"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"高さを高くする"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"次を表示"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"前を表示"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ロック画面ウィジェット"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ウィジェットを使用してアプリを起動するには、本人確認が必要です。タブレットがロックされた状態でも他のユーザーにウィジェットが表示されますので、注意してください。一部のウィジェットについてはロック画面での使用を想定していないため、ロック画面への追加は危険な場合があります。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>は会話機能に対応していません"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"フィードバック"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"閉じる"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"次回から表示しない"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"着信通知は変更できません。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"このグループの通知はここでは設定できません"</string> diff --git a/packages/SystemUI/res/values-ja/tiles_states_strings.xml b/packages/SystemUI/res/values-ja/tiles_states_strings.xml index 81c10e7d0ab8..1282f5702483 100644 --- a/packages/SystemUI/res/values-ja/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ja/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"OFF"</item> <item msgid="5908720590832378783">"ON"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 18522da3dfb4..b599220a3cc0 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ვიჯეტის არჩევის გაუქმება"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"სიმაღლის შემცირება"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"სიმაღლის გაზრდა"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"შემდეგის ჩვენება"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"წინას ჩვენება"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"დაბლოკილი ეკრანის ვიჯეტები"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"უნდა დაადასტუროთ თქვენი ვინაობა, რათა გახსნათ აპი ვიჯეტის გამოყენებით. გაითვალისწინეთ, რომ ნებისმიერს შეუძლია მათი ნახვა, მაშინაც კი, როცა ტაბლეტი დაბლოკილია. ზოგი ვიჯეტი შეიძლება არ იყოს გათვლილი თქვენი დაბლოკილი ეკრანისთვის და მათი აქ დამატება შეიძლება სახიფათო იყოს."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"გასაგებია"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს მიმოწერის ფუნქციების მხარდაჭერა"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"გამოხმაურება"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"დახურვა"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"აღარ მაჩვენო"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ამ შეტყობინებების შეცვლა შეუძლებელია."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ზარის შეტყობინებების შეცვლა შეუძლებელია."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"შეტყობინებების ამ ჯგუფის კონფიგურირება აქ შეუძლებელია"</string> diff --git a/packages/SystemUI/res/values-ka/tiles_states_strings.xml b/packages/SystemUI/res/values-ka/tiles_states_strings.xml index 6e62ed4ee74a..81fc54d8381e 100644 --- a/packages/SystemUI/res/values-ka/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ka/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"გამორთული"</item> <item msgid="5908720590832378783">"ჩართული"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 83af7c8b8607..bf12aca88d5d 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -114,7 +114,7 @@ <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="4882406311415082016">"Осы экранды жазу"</string> <string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="4169494703993148253">"%s экранын жазу"</string> <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"Бүкіл экранды жазған кезде, онда көрінетін барлық нәрсе жазылады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string> - <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Қолданбаны жазған кезде, онда көрінетін не ойнатылатын барлық нәрсе жазылады. Сондықтан құпия сөздерді, төлем туралы мәліметті, хабарларды немесе басқа құпия ақпаратты енгізген кезде сақ болыңыз."</string> + <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"Қолданбаны жазған кезде, онда көрінетін не ойнатылатын барлық нәрсе жазылады. Сондықтан құпия сөздерге, төлем туралы мәліметке, хабарларға, фотосуреттерге, дыбыстар мен бейнелерге сақ болыңыз."</string> <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"Экранды жазу"</string> <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"Жазатын қолданба экранын таңдау"</string> <string name="screenrecord_audio_label" msgid="6183558856175159629">"Аудио жазу"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"виджетті таңдаудан алу"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Биіктігін төмендету"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Биіктігін арттыру"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Келесіні көрсету"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Алдыңғыны көрсету"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Құлып экранының виджеттері"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Қолданбаны виджет көмегімен ашу үшін жеке басыңызды растауыңыз керек. Сондай-ақ басқалар оларды планшетіңіз құлыптаулы кезде де көре алатынын ескеріңіз. Кейбір виджеттер құлып экранына арналмаған болады, сондықтан оларды мұнда қосу қауіпсіз болмауы мүмкін."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Түсінікті"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгіме функцияларын қолдамайды."</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Пікір"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Жабу"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Қайта көрсетілмесін"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Қоңырау туралы хабарландыруларды өзгерту мүмкін емес."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Бүктемелі құрылғы ашылып жатыр."</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Бүктемелі құрылғы аударылып жатыр."</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Алдыңғы экран қосылды."</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Ішкі экранды пайдалану үшін жылжытыңыз."</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"жабық"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ашық"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-kk/tiles_states_strings.xml b/packages/SystemUI/res/values-kk/tiles_states_strings.xml index 66deff6d7135..32562c652750 100644 --- a/packages/SystemUI/res/values-kk/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-kk/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Өшірулі"</item> <item msgid="5908720590832378783">"Қосулы"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 569ecd3d1677..e12fd1315636 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ដកការជ្រើសរើសធាតុក្រាហ្វិក"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"បន្ថយកម្ពស់"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"បង្កើនកម្ពស់"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"បង្ហាញកម្មវិធីចាក់មេឌៀបន្ទាប់"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"បង្ហាញកម្មវិធីចាក់មេឌៀមុន"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ធាតុក្រាហ្វិកលើអេក្រង់ចាក់សោ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ដើម្បីបើកកម្មវិធីដោយប្រើធាតុក្រាហ្វិក អ្នកនឹងត្រូវផ្ទៀងផ្ទាត់ថាជាអ្នក។ ទន្ទឹមនឹងនេះ សូមចងចាំថា នរណាក៏អាចមើលធាតុក្រាហ្វិកបាន សូម្បីពេលថេប្លេតរបស់អ្នកជាប់សោក៏ដោយ។ ធាតុក្រាហ្វិកមួយចំនួនប្រហែលមិនត្រូវបានរចនាឡើងសម្រាប់អេក្រង់ចាក់សោរបស់អ្នកទេ និងមិនមានសុវត្ថិភាពឡើយ បើបញ្ចូលទៅទីនេះ។"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"យល់ហើយ"</string> @@ -542,7 +544,7 @@ <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"ចូលប្រើប្រាស់ធាតុក្រាហ្វិក និងធាតុរក្សាអេក្រង់ដែលអ្នកពេញចិត្តពេលសាកថ្ម។"</string> <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"ចាប់ផ្ដើម"</string> <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"បង្ហាញធាតុរក្សាអេក្រង់សំណព្វរបស់អ្នក ពេលកំពុងសាកថ្ម"</string> - <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរអ្នកប្រើ"</string> + <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរអ្នកប្រើប្រាស់"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ម៉ឺនុយទាញចុះ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យទាំងអស់ក្នុងវគ្គនេះនឹងត្រូវលុប។"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"សូមស្វាគមន៍ការត្រឡប់មកវិញ, ភ្ញៀវ!"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើមុខងារសន្ទនាបានទេ"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"មតិកែលម្អ"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"ច្រានចោល"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"កុំបង្ហាញម្ដងទៀត"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាចកែប្រែការជូនដំណឹងទាំងនេះបានទេ។"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"មិនអាចកែប្រែការជូនដំណឹងអំពីការហៅទូរសព្ទបានទេ។"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"មិនអាចកំណត់រចនាសម្ព័ន្ធក្រុមការជូនដំណឹងនេះនៅទីនេះបានទេ"</string> diff --git a/packages/SystemUI/res/values-km/tiles_states_strings.xml b/packages/SystemUI/res/values-km/tiles_states_strings.xml index 71b12ca8ff62..0e47250b8f33 100644 --- a/packages/SystemUI/res/values-km/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-km/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"បិទ"</item> <item msgid="5908720590832378783">"បើក"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 5bcd986b2bad..3bb4e4de91ea 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ವಿಜೆಟ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಬೇಡಿ"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ಎತ್ತರವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ಎತ್ತರವನ್ನು ಹೆಚ್ಚಿಸಿ"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"ಮುಂದಿನದನ್ನು ತೋರಿಸಿ"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"ಹಿಂದಿನದನ್ನು ತೋರಿಸಿ"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ವಿಜೆಟ್ಗಳು"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ವಿಜೆಟ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಆ್ಯಪ್ ತೆರೆಯಲು, ಇದು ನೀವೇ ಎಂದು ನೀವು ದೃಢೀಕರಿಸಬೇಕಾಗುತ್ತದೆ. ಅಲ್ಲದೆ, ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಲಾಕ್ ಆಗಿದ್ದರೂ ಸಹ ಯಾರಾದರೂ ಅವುಗಳನ್ನು ವೀಕ್ಷಿಸಬಹುದು ಎಂಬುದನ್ನು ನೆನಪಿನಲ್ಲಿಡಿ. ಕೆಲವು ವಿಜೆಟ್ಗಳು ನಿಮ್ಮ ಲಾಕ್ ಸ್ಕ್ರೀನ್ಗಾಗಿ ಉದ್ದೇಶಿಸದೇ ಇರಬಹುದು ಮತ್ತು ಇಲ್ಲಿ ಸೇರಿಸುವುದು ಸುರಕ್ಷಿತವಲ್ಲದಿರಬಹುದು."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ಅರ್ಥವಾಯಿತು"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"ಸಂವಾದ ಫೀಚರ್ಗಳನ್ನು <xliff:g id="APP_NAME">%1$s</xliff:g> ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ಫೀಡ್ಬ್ಯಾಕ್"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"ವಜಾಗೊಳಿಸಿ"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ಕರೆ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ಈ ಗುಂಪಿನ ಅಧಿಸೂಚನೆಗಳನ್ನು ಇಲ್ಲಿ ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿರುವುದಿಲ್ಲ"</string> diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml index 49c688abff72..b3543f9d2638 100644 --- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ಆಫ್ ಆಗಿದೆ"</item> <item msgid="5908720590832378783">"ಆನ್ ಆಗಿದೆ"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index fd2c62e16a17..33f54b69b4d5 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"위젯 선택 해제"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"높이 줄이기"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"높이 늘리기"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"다음 표시"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"이전 표시"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"잠금 화면 위젯"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"위젯을 사용하여 앱을 열려면 본인 인증을 해야 합니다. 또한 태블릿이 잠겨 있더라도 누구나 볼 수 있다는 점을 유의해야 합니다. 일부 위젯은 잠금 화면에 적합하지 않고 여기에 추가하기에 안전하지 않을 수 있습니다."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"확인"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"의견"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"닫기"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"다시 표시하지 않음"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"전화 알림은 수정할 수 없습니다."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"폴더블 기기를 펼치는 모습"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"폴더블 기기를 뒤집는 모습"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"전면 화면 켜짐"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"슬라이드하여 내부 화면 사용"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"접은 상태"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"펼친 상태"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-ko/tiles_states_strings.xml b/packages/SystemUI/res/values-ko/tiles_states_strings.xml index 002d38e71e96..c512435020dd 100644 --- a/packages/SystemUI/res/values-ko/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ko/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"사용 안함"</item> <item msgid="5908720590832378783">"사용"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 1916cbc21270..e764badc2d37 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"виджетти тандоодон чыгаруу"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Бийиктигин азайтуу"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Бийиктигин көбөйтүү"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Кийинкини көрсөтүү"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Мурункуну көрсөтүү"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Кулпуланган экрандагы виджеттер"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Колдонмону виджет аркылуу ачуу үчүн өзүңүздү ырасташыңыз керек. Алар кулпуланган планшетиңизде да көрүнүп турат. Кээ бир виджеттерди кулпуланган экранда колдоно албайсыз, андыктан аларды ал жерге кошпой эле койгонуңуз оң."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Түшүндүм"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда оозеки сүйлөшкөнгө болбойт"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Пикир билдирүү"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Жабуу"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Экинчи көрсөтүлбөсүн"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Чалуу билдирмелерин өзгөртүүгө болбойт."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Бул билдирмелердин тобун бул жерде конфигурациялоого болбойт"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ачылып турган бүктөлмө түзмөк"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Оодарылып жаткан бүктөлмө түзмөк"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Маңдайкы экран күйгүзүлдү"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Ички экранды колдонуу үчүн экранды сүрүп коюңуз"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"бүктөлгөн"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ачылган"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-ky/tiles_states_strings.xml b/packages/SystemUI/res/values-ky/tiles_states_strings.xml index 4834dbc69246..47e36da6126f 100644 --- a/packages/SystemUI/res/values-ky/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ky/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Өчүк"</item> <item msgid="5908720590832378783">"Күйүк"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index f61186d19e0b..3236b2e2faad 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ຍົກເລີກການເລືອກວິດເຈັດ"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ຫຼຸດຄວາມສູງ"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ເພີ່ມຄວາມສູງ"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"ສະແດງເພງຖັດໄປ"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"ສະແດງເພງກ່ອນໜ້າ"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ວິດເຈັດໃນໜ້າຈໍລັອກ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ເພື່ອເປີດແອັບໂດຍໃຊ້ວິດເຈັດ, ທ່ານຈະຕ້ອງຢັ້ງຢືນວ່າແມ່ນທ່ານ. ນອກຈາກນັ້ນ, ກະລຸນາຮັບຊາບວ່າທຸກຄົນສາມາດເບິ່ງຂໍ້ມູນດັ່ງກ່າວໄດ້, ເຖິງແມ່ນວ່າແທັບເລັດຂອງທ່ານຈະລັອກຢູ່ກໍຕາມ. ວິດເຈັດບາງຢ່າງອາດບໍ່ໄດ້ມີໄວ້ສຳລັບໜ້າຈໍລັອກຂອງທ່ານ ແລະ ອາດບໍ່ປອດໄພທີ່ຈະເພີ່ມໃສ່ບ່ອນນີ້."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ເຂົ້າໃຈແລ້ວ"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບຄຸນສົມບັດການສົນທະນາ"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ຄຳຕິຊົມ"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"ປິດໄວ້"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ບໍ່ຕ້ອງສະແດງອີກ"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນການໂທໄດ້."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ບໍ່ສາມາດຕັ້ງຄ່າກຸ່ມການແຈ້ງເຕືອນນີ້ຢູ່ບ່ອນນີ້ໄດ້"</string> diff --git a/packages/SystemUI/res/values-lo/tiles_states_strings.xml b/packages/SystemUI/res/values-lo/tiles_states_strings.xml index bc63895f3bc6..71e084a21b7c 100644 --- a/packages/SystemUI/res/values-lo/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-lo/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ປິດ"</item> <item msgid="5908720590832378783">"ເປີດ"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 88f9399c3a56..25208b0ca6e2 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"atšaukti valdiklio pasirinkimą"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Sumažinti aukštį"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Padidinti aukštį"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Rodyti kitą mediją"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Rodyti ankstesnę mediją"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Užrakinimo ekrano valdikliai"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Kad galėtumėte atidaryti programą naudodami valdiklį, turėsite patvirtinti savo tapatybę. Be to, atminkite, kad bet kas gali peržiūrėti valdiklius net tada, kai planšetinis kompiuteris užrakintas. Kai kurie valdikliai gali būti neskirti jūsų užrakinimo ekranui ir gali būti nesaugu juos čia pridėti."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Supratau"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko pokalbių funkcijų"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Atsiliepimai"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Uždaryti"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Neberodyti"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Skambučių pranešimų keisti negalima."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Šios grupės pranešimai čia nekonfigūruojami"</string> diff --git a/packages/SystemUI/res/values-lt/tiles_states_strings.xml b/packages/SystemUI/res/values-lt/tiles_states_strings.xml index 12f8b6ce02cf..893d6aef3069 100644 --- a/packages/SystemUI/res/values-lt/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-lt/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Išjungta"</item> <item msgid="5908720590832378783">"Įjungta"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index e0e38a140bee..bf1ef9692c71 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -125,7 +125,7 @@ <string name="screenrecord_continue" msgid="4055347133700593164">"Sākt"</string> <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Notiek ekrāna satura ierakstīšana."</string> <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Notiek ekrāna satura un audio ierakstīšana."</string> - <string name="screenrecord_taps_label" msgid="1595690528298857649">"Rādīt pieskārienus pie ekrāna"</string> + <string name="screenrecord_taps_label" msgid="1595690528298857649">"Rādīt pieskārienus ekrānam"</string> <string name="screenrecord_stop_label" msgid="72699670052087989">"Pārtraukt"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Kopīgot"</string> <string name="screenrecord_save_title" msgid="1886652605520893850">"Ekrāna ieraksts ir saglabāts"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"noņemt logrīka atlasi"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Samazināt augstumu"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Palielināt augstumu"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Rādīt nākamo"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Rādīt iepriekšējo"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Bloķēšanas ekrāna logrīki"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Lai atvērtu lietotni, izmantojot logrīku, jums būs jāapstiprina sava identitāte. Turklāt ņemiet vērā, ka ikviens var skatīt logrīkus, pat ja planšetdators ir bloķēts. Iespējams, daži logrīki nav paredzēti izmantošanai bloķēšanas ekrānā, un var nebūt droši tos šeit pievienot."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Labi"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstītas sarunu funkcijas."</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Atsauksmes"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Nerādīt"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Vairs nerādīt"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Paziņojumus par zvaniem nevar modificēt."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Šeit nevar konfigurēt šo paziņojumu grupu."</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Salokāma ierīce tiek atlocīta"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Salokāma ierīce tiek apgriezta"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Priekšējais ekrāns ir ieslēgts"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Velciet, lai izmantotu iekšējo ekrānu."</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"aizvērta"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"atvērta"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-lv/tiles_states_strings.xml b/packages/SystemUI/res/values-lv/tiles_states_strings.xml index 14948360d102..732975135494 100644 --- a/packages/SystemUI/res/values-lv/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-lv/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Izslēgts"</item> <item msgid="5908720590832378783">"Ieslēgts"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 0a9ca89fd4d3..e34d9d88cc82 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"поништи го изборот на виџетот"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Намали ја висината"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Зголеми ја висината"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Прикажи следно"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Прикажи претходно"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виџети на заклучен екран"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"За да отворите апликација со помош на виџет, ќе треба да потврдите дека сте вие. Покрај тоа, имајте предвид дека секој може да ги гледа виџетите, дури и кога вашиот таблет е заклучен. Некои виџети можеби не се наменети за вашиот заклучен екран, па можеби не е безбедно да се додадат овде."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Сфатив"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува функции за разговор"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Повратни информации"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Отфрли"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Не прикажувај повторно"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Овие известувања не може да се изменат"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Известувањата за повици не може да се изменат."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Оваа група известувања не може да се конфигурира тука"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Преклопувачки уред се отклопува"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Преклопувачки уред се врти"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Предниот екран е вклучен"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Лизгајте за да го користите внатрешниот екран"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"затворен"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"отворен"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-mk/tiles_states_strings.xml b/packages/SystemUI/res/values-mk/tiles_states_strings.xml index 17545c332b63..67baf7c305ce 100644 --- a/packages/SystemUI/res/values-mk/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-mk/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Исклучено"</item> <item msgid="5908720590832378783">"Вклучено"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 8ef9b7904765..226822a606bf 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"വിജറ്റ് തിരഞ്ഞെടുത്തത് മാറ്റുക"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ഉയരം കുറയ്ക്കുക"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ഉയരം കൂട്ടുക"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"അടുത്തത് കാണിക്കുക"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"മുമ്പത്തേത് കാണിക്കുക"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ലോക്ക് സ്ക്രീൻ വിജറ്റുകൾ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"വിജറ്റ് ഉപയോഗിച്ച് ഒരു ആപ്പ് തുറക്കാൻ, ഇത് നിങ്ങൾ തന്നെയാണെന്ന് പരിശോധിച്ചുറപ്പിക്കേണ്ടതുണ്ട്. നിങ്ങളുടെ ടാബ്ലെറ്റ് ലോക്കായിരിക്കുമ്പോഴും എല്ലാവർക്കും അത് കാണാനാകുമെന്നതും ഓർക്കുക. ചില വിജറ്റുകൾ നിങ്ങളുടെ ലോക്ക് സ്ക്രീനിന് ഉള്ളതായിരിക്കില്ല, അവ ഇവിടെ ചേർക്കുന്നത് സുരക്ഷിതവുമായിരിക്കില്ല."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"മനസ്സിലായി"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"സംഭാഷണ ഫീച്ചറുകളെ <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ഫീഡ്ബാക്ക്"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"ഡിസ്മിസ് ചെയ്യുക"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"വീണ്ടും കാണിക്കരുത്"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"കോൾ അറിയിപ്പുകൾ പരിഷ്കരിക്കാനാകുന്നില്ല."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"അറിയിപ്പുകളുടെ ഈ ഗ്രൂപ്പ് ഇവിടെ കോണ്ഫിഗര് ചെയ്യാൻ കഴിയില്ല"</string> diff --git a/packages/SystemUI/res/values-ml/tiles_states_strings.xml b/packages/SystemUI/res/values-ml/tiles_states_strings.xml index 689fe85bf3e6..8639c1030cbe 100644 --- a/packages/SystemUI/res/values-ml/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ml/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ഓഫാണ്"</item> <item msgid="5908720590832378783">"ഓണാണ്"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index feca24111f3d..06b62e9ae8eb 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"виджетийн сонголтыг болиулах"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Намсгах"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Өндөрсгөх"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Дараагийнхыг харуулах"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Өмнөхийг харуулах"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Түгжээтэй дэлгэцийн виджет"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Виджет ашиглан аппыг нээхийн тулд та өөрийгөө мөн болохыг баталгаажуулах шаардлагатай болно. Мөн таны таблет түгжээтэй байсан ч тэдгээрийг дурын хүн үзэж болохыг санаарай. Зарим виджет таны түгжээтэй дэлгэцэд зориулагдаагүй байж магадгүй ба энд нэмэхэд аюултай байж болзошгүй."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ойлголоо"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь харилцан ярианы онцлогуудыг дэмждэггүй"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Санал хүсэлт"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Хаах"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Дахиж бүү харуул"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Дуудлагын мэдэгдлийг өөрчлөх боломжгүй."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Энэ бүлэг мэдэгдлийг энд тохируулах боломжгүй байна"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Эвхэгддэг төхөөрөмжийг дэлгэж байна"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Эвхэгддэг төхөөрөмжийг хөнтөрч байна"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Нүүрэн талын дэлгэцийг асаасан"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Дотоод дэлгэцийг ашиглахын тулд гулсуулна уу"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"эвхсэн"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"дэлгэсэн"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-mn/tiles_states_strings.xml b/packages/SystemUI/res/values-mn/tiles_states_strings.xml index 94e393961988..678033cf4a07 100644 --- a/packages/SystemUI/res/values-mn/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-mn/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Унтраалттай"</item> <item msgid="5908720590832378783">"Асаалттай"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index a3c45f3f0870..4c2fd29355ce 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"विजेटची निवड रद्द करा"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"उंची कमी करा"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"उंची वाढवा"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"पुढील दाखवा"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"मागील दाखवा"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लॉक स्क्रीन विजेट"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"विजेट वापरून अॅप उघडण्यासाठी, तुम्हाला हे तुम्हीच असल्याची पडताळणी करावी लागेल. तसेच, लक्षात ठेवा, तुमचा टॅबलेट लॉक असतानादेखील कोणीही ती पाहू शकते. काही विजेट कदाचित तुमच्या लॉक स्क्रीनसाठी नाहीत आणि ती इथे जोडणे असुरक्षित असू शकते."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"समजले"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे संभाषण वैशिष्ट्यांना सपोर्ट करत नाही"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"फीडबॅक"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"डिसमिस करा"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"पुन्हा दाखवू नका"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कॉलशी संबंधित सूचनांमध्ये फेरबदल केला जाऊ शकत नाही."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"या सूचनांचा संच येथे कॉन्फिगर केला जाऊ शकत नाही"</string> @@ -1523,8 +1530,8 @@ <string name="tutorial_animation_content_description" msgid="2698816574982370184">"ट्यूटोरियल अॅनिमेशन थांबवण्यासाठी किंवा पुन्हा सुरू करण्यासाठी प्ले करा वर क्लिक करा."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड बॅकलाइट"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d पैकी %1$d पातळी"</string> - <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string> - <string name="home_controls_dream_description" msgid="4644150952104035789">"स्क्रीनसेव्हर म्हणून होम कंट्रोल झटपट ॲक्सेस करा"</string> + <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल्स"</string> + <string name="home_controls_dream_description" msgid="4644150952104035789">"स्क्रीनसेव्हर म्हणून होम कंट्रोल्स झटपट ॲक्सेस करा"</string> <string name="volume_undo_action" msgid="5815519725211877114">"पहिल्यासारखे करा"</string> <string name="back_edu_toast_content" msgid="4530314597378982956">"मागे जाण्यासाठी, टचपॅडवर तीन बोटांनी डावीकडे किंवा उजवीकडे स्वाइप करा"</string> <string name="home_edu_toast_content" msgid="3381071147871955415">"होमवर जाण्यासाठी, टचपॅडवर तीन बोटांनी वरती स्वाइप करा"</string> diff --git a/packages/SystemUI/res/values-mr/tiles_states_strings.xml b/packages/SystemUI/res/values-mr/tiles_states_strings.xml index cbaefb9367c2..ec876598a95d 100644 --- a/packages/SystemUI/res/values-mr/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-mr/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"बंद आहे"</item> <item msgid="5908720590832378783">"सुरू आहे"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index bb7dcb86428f..93f25ffc012e 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"nyahpilih widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Kurangkan ketinggian"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Tambahkan ketinggian"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Tunjukkan seterusnya"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Tunjukkan sebelumnya"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widget skrin kunci"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Untuk membuka apl menggunakan widget, anda perlu mengesahkan identiti anda. Selain itu, perlu diingat bahawa sesiapa sahaja boleh melihat widget tersebut, walaupun semasa tablet anda dikunci. Sesetengah widget mungkin tidak sesuai untuk skrin kunci anda dan mungkin tidak selamat untuk ditambahkan di sini."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong ciri perbualan"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Maklum balas"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Ketepikan"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Jangan tunjukkan lagi"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Pemberitahuan panggilan tidak boleh diubah suai."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Kumpulan pemberitahuan ini tidak boleh dikonfigurasikan di sini"</string> diff --git a/packages/SystemUI/res/values-ms/tiles_states_strings.xml b/packages/SystemUI/res/values-ms/tiles_states_strings.xml index 3c78bccfef53..6dc9827997f7 100644 --- a/packages/SystemUI/res/values-ms/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ms/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Mati"</item> <item msgid="5908720590832378783">"Hidup"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 0219f695c6f0..bed07ef4cf49 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ဝိဂျက် ပြန်ဖြုတ်ရန်"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"အမြင့်ကို လျှော့ရန်"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"အမြင့်ကို တိုးရန်"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"နောက်တစ်ခု ပြပါ"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"ယခင်တစ်ခု ပြပါ"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"လော့ခ်မျက်နှာပြင် ဝိဂျက်များ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ဝိဂျက်သုံး၍ အက်ပ်ဖွင့်ရန်အတွက် သင်ဖြစ်ကြောင်း အတည်ပြုရန်လိုသည်။ ထို့ပြင် သင့်တက်ဘလက် လော့ခ်ချထားချိန်၌ပင် မည်သူမဆို ၎င်းတို့ကို ကြည့်နိုင်ကြောင်း သတိပြုပါ။ ဝိဂျက်အချို့ကို လော့ခ်မျက်နှာပြင်အတွက် ရည်ရွယ်ထားခြင်း မရှိသဖြင့် ဤနေရာတွင် ထည့်ပါက မလုံခြုံနိုင်ပါ။"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"နားလည်ပြီ"</string> @@ -542,7 +544,7 @@ <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"အားသွင်းနေစဉ် အကြိုက်ဆုံးဝိဂျက်များ၊ စခရင်နားချိန်ပုံများ ကြည့်နိုင်သည်။"</string> <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"စကြစို့"</string> <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"အားသွင်းနေစဉ် သင့်အကြိုက်ဆုံး စခရင်နားချိန်ပုံများကို ပြသည်"</string> - <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string> + <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူပြောင်းရန်"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ဆွဲချမီနူး"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ဧည့်သည်ကို ပြန်လည် ကြိုဆိုပါသည်။"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းဝန်ဆောင်မှုများကို မပံ့ပိုးပါ"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"အကြံပြုချက်"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"ပယ်ရန်"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ထပ်မပြပါနှင့်"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ခေါ်ဆိုမှုအကြောင်းကြားချက်များကို ပြင်၍မရပါ။"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ဤအကြောင်းကြားချက်အုပ်စုကို ဤနေရာတွင် စီစဉ်သတ်မှတ်၍ မရပါ"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ခေါက်နိုင်သောစက်ကို ဖြန့်လိုက်သည်"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ခေါက်နိုင်သောစက်ကို တစ်ဘက်သို့ လှန်လိုက်သည်"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ရှေ့စခရင် ဖွင့်ထားသည်"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"အတွင်းဘက်ဖန်သားပြင် သုံးရန် ဘေးတိုက်ပွတ်ဆွဲပါ"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ခေါက်ထားသည်"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ဖြန့်ထားသည်"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-my/tiles_states_strings.xml b/packages/SystemUI/res/values-my/tiles_states_strings.xml index 9675cb5b46b4..424b4b9ef33e 100644 --- a/packages/SystemUI/res/values-my/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-my/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ပိတ်"</item> <item msgid="5908720590832378783">"ဖွင့်"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 15e568b1c687..7e87efc4f0dc 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"velg bort modul"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Reduser høyden"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Øk høyden"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Vis neste"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Vis forrige"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Låseskjermmoduler"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"For å åpne en app ved hjelp av en modul må du bekrefte at det er deg. Husk også at hvem som helst kan se dem, selv om nettbrettet er låst. Noen moduler er kanskje ikke laget for å være på låseskjermen og kan være utrygge å legge til der."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Greit"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalefunksjoner"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Tilbakemelding"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Lukk"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ikke vis igjen"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Anropsvarsler kan ikke endres."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Denne varselgruppen kan ikke konfigureres her"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En foldbar enhet blir brettet ut"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En foldbar enhet blir snudd"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Frontskjermen er slått på"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Dra for å bruke den indre skjermen"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"lagt sammen"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"åpen"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-nb/tiles_states_strings.xml b/packages/SystemUI/res/values-nb/tiles_states_strings.xml index bd5b69279714..bbeafd86ecc0 100644 --- a/packages/SystemUI/res/values-nb/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-nb/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Av"</item> <item msgid="5908720590832378783">"På"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 02285f209b88..cc07b7fa1001 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"विजेटको चयन रद्द गर्नुहोस्"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"उचाइ घटाउनुहोस्"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"उचाइ बढाउनुहोस्"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"अर्को देखाउनुहोस्"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"अघिल्लो देखाउनुहोस्"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"लक स्क्रिन विजेटहरू"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"विजेट प्रयोग गरी एप खोल्न तपाईंले आफ्नो पहिचान पुष्टि गर्नु पर्ने हुन्छ। साथै, तपाईंको ट्याब्लेट लक भएका बेला पनि सबै जनाले तिनलाई देख्न सक्छन् भन्ने कुरा ख्याल गर्नुहोस्। केही विजेटहरू लक स्क्रिनमा प्रयोग गर्ने उद्देश्यले नबनाइएका हुन सक्छन् र तिनलाई यहाँ हाल्नु सुरक्षित नहुन सक्छ।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"बुझेँ"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापसम्बन्धी सुविधा प्रयोग गर्न मिल्दैन"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"प्रतिक्रिया"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"हटाउनुहोस्"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"फेरि नदेखाउनुहोस्"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"कलसम्बन्धी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"यहाँबाट सूचनाहरूको यो समूह कन्फिगर गर्न सकिँदैन"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"फोल्डेबल डिभाइस अनफोल्ड गरेको देखाइएको एनिमेसन"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"फोल्डेबल डिभाइस यताउता पल्टाएर देखाइएको एनिमेसन"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"अगाडिको स्क्रिन अन गरिएको छ"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"भित्री स्क्रिन प्रयोग गर्न स्लाइड गर्नुहोस्"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"फोल्ड गरिएको"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"अनफोल्ड गरिएको"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-ne/tiles_states_strings.xml b/packages/SystemUI/res/values-ne/tiles_states_strings.xml index 2dd209d8565b..de3baa0a33cf 100644 --- a/packages/SystemUI/res/values-ne/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ne/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"अफ छ"</item> <item msgid="5908720590832378783">"अन छ"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 99c8838db1cc..b778cecfee22 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"widget deselecteren"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Hoogte verkleinen"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Hoogte vergroten"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Volgende tonen"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Vorige tonen"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets op het vergrendelscherm"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Als je een app wilt openen met een widget, moet je verifiëren dat jij het bent. Houd er ook rekening mee dat iedereen ze kan bekijken, ook als je tablet vergrendeld is. Bepaalde widgets zijn misschien niet bedoeld voor je vergrendelscherm en kunnen hier niet veilig worden toegevoegd."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksfuncties"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Sluiten"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Niet meer tonen"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Gespreksmeldingen kunnen niet worden aangepast."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Deze groep meldingen kan hier niet worden ingesteld"</string> diff --git a/packages/SystemUI/res/values-nl/tiles_states_strings.xml b/packages/SystemUI/res/values-nl/tiles_states_strings.xml index 221749c2c90b..90572b674ab4 100644 --- a/packages/SystemUI/res/values-nl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-nl/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Uit"</item> <item msgid="5908720590832378783">"Aan"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 5847a9a968ba..0ef622b6b6eb 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -128,8 +128,8 @@ <string name="screenrecord_taps_label" msgid="1595690528298857649">"ସ୍କ୍ରିନରେ ସ୍ପର୍ଶଗୁଡ଼ିକ ଦେଖାନ୍ତୁ"</string> <string name="screenrecord_stop_label" msgid="72699670052087989">"ବନ୍ଦ କରନ୍ତୁ"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"ସେୟାର୍ କରନ୍ତୁ"</string> - <string name="screenrecord_save_title" msgid="1886652605520893850">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ସେଭ୍ କରାଯାଇଛି"</string> - <string name="screenrecord_save_text" msgid="3008973099800840163">"ଦେଖିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string> + <string name="screenrecord_save_title" msgid="1886652605520893850">"ସ୍କ୍ରିନ ରେକର୍ଡିଂ ସେଭ କରାଯାଇଛି"</string> + <string name="screenrecord_save_text" msgid="3008973099800840163">"ଦେଖିବାକୁ ଟାପ କରନ୍ତୁ"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ସ୍କ୍ରିନ ରେକର୍ଡିଂ ସେଭ କରିବାରେ ତ୍ରୁଟି"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ସ୍କ୍ରିନ୍ ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବାରେ ତ୍ରୁଟି"</string> <string name="screenrecord_stop_dialog_title" msgid="8716193661764511095">"ରେକର୍ଡିଂ ବନ୍ଦ କରିବେ?"</string> @@ -360,7 +360,7 @@ <string name="quick_settings_connected" msgid="3873605509184830379">"ସଂଯୁକ୍ତ"</string> <string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"କନେକ୍ଟ ରହିଛି, ବ୍ୟାଟେରୀ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="quick_settings_connecting" msgid="2381969772953268809">"ସଂଯୋଗ କରୁଛି..."</string> - <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"ହଟସ୍ପଟ୍"</string> + <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"ହଟସ୍ପଟ"</string> <string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"ଚାଲୁ ହେଉଛି…"</string> <string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"ଡାଟା ସେଭର୍ ଅନ୍ ଅଛି"</string> <string name="quick_settings_hotspot_secondary_label_num_devices" msgid="7536823087501239457">"{count,plural, =1{#ଟି ଡିଭାଇସ}other{#ଟି ଡିଭାଇସ}}"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ୱିଜେଟକୁ ଅଚୟନ କରନ୍ତୁ"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ଉଚ୍ଚତାକୁ କମ କରନ୍ତୁ"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ଉଚ୍ଚତାକୁ ବଢ଼ାନ୍ତୁ"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"ପରବର୍ତ୍ତୀ ନେଭିଗେସନ ପଏଣ୍ଟ ଦେଖାନ୍ତୁ"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"ପୂର୍ବବର୍ତ୍ତୀ ଦେଖାନ୍ତୁ"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ଲକ ସ୍କ୍ରିନ ୱିଜେଟ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ଏକ ୱିଜେଟ ବ୍ୟବହାର କରି ଗୋଟିଏ ଆପ ଖୋଲିବା ପାଇଁ ଏହା ଆପଣ ଅଟନ୍ତି ବୋଲି ଆପଣଙ୍କୁ ଯାଞ୍ଚ କରିବାକୁ ହେବ। ଆହୁରି ମଧ୍ୟ, ଆପଣଙ୍କ ଟାବଲେଟ ଲକ ଥିଲେ ମଧ୍ୟ ଯେ କୌଣସି ବ୍ୟକ୍ତି ଏହାକୁ ଭ୍ୟୁ କରିପାରିବେ ବୋଲି ମନେ ରଖନ୍ତୁ। କିଛି ୱିଜେଟ ଆପଣଙ୍କ ଲକ ସ୍କ୍ରିନ ପାଇଁ ଉଦ୍ଦିଷ୍ଟ ହୋଇନଥାଇପାରେ ଏବଂ ଏଠାରେ ଯୋଗ କରିବା ଅସୁରକ୍ଷିତ ହୋଇପାରେ।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ବୁଝିଗଲି"</string> @@ -757,7 +759,7 @@ <string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string> <string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ହେଲେ"</string> <string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ବେଳେ"</string> - <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ହଟସ୍ପଟ୍"</string> + <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ହଟସ୍ପଟ"</string> <string name="accessibility_status_bar_satellite_no_connection" msgid="3001571744269917762">"ସାଟେଲାଇଟ, କୌଣସି କନେକ୍ସନ ନାହିଁ"</string> <string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"ସାଟେଲାଇଟ, ଦୁର୍ବଳ କନେକ୍ସନ"</string> <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"ସାଟେଲାଇଟ, ଭଲ କନେକ୍ସନ"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ଫିଚରଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ମତାମତ"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"ଖାରଜ କରନ୍ତୁ"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ପୁଣି ଶୋ କରନ୍ତୁ ନାହିଁ"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"କଲ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରାଯାଇପାରିବ ନାହିଁ।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ଏଠାରେ ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ଗ୍ରୁପ୍ କନଫ୍ୟୁଗର୍ କରାଯାଇପାରିବ ନାହିଁ"</string> @@ -955,7 +962,7 @@ <item msgid="5874146774389433072">"ଡାହାଣକୁ-ଆଉଜେଇବା"</item> </string-array> <string name="save" msgid="3392754183673848006">"ସେଭ କରନ୍ତୁ"</string> - <string name="reset" msgid="8715144064608810383">"ରିସେଟ୍ କରନ୍ତୁ"</string> + <string name="reset" msgid="8715144064608810383">"ରିସେଟ କରନ୍ତୁ"</string> <string name="clipboard" msgid="8517342737534284617">"କ୍ଲିପ୍ବୋର୍ଡ"</string> <string name="accessibility_key" msgid="3471162841552818281">"କଷ୍ଟମ୍ ନାଭିଗେଶନ୍ ବଟନ୍"</string> <string name="left_keycode" msgid="8211040899126637342">"ବାମ କୀ\'କୋଡ୍"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଅନଫୋଲ୍ଡ କରାଯାଉଛି"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"ଫୋଲ୍ଡ କରାଯାଇପାରୁଥିବା ଡିଭାଇସକୁ ଫ୍ଲିପ କରାଯାଉଛି"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ସାମ୍ନା ସ୍କ୍ରିନ ଚାଲୁ ଅଛି"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"ଭିତର ସ୍କ୍ରିନକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ସ୍ଲାଇଡ କରନ୍ତୁ"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"ଫୋଲ୍ଡେଡ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"ଅନଫୋଲ୍ଡେଡ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-or/tiles_states_strings.xml b/packages/SystemUI/res/values-or/tiles_states_strings.xml index 8d230739caf7..c9c319892ab8 100644 --- a/packages/SystemUI/res/values-or/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-or/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ବନ୍ଦ ଅଛି"</item> <item msgid="5908720590832378783">"ଚାଲୁ ଅଛି"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 17757b896f5b..4be78a32282c 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ਵਿਜੇਟ ਨੂੰ ਅਣਚੁਣਿਆ ਕਰੋ"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ਉਚਾਈ ਘਟਾਓ"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ਉਚਾਈ ਵਧਾਓ"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"ਅਗਲਾ ਦਿਖਾਓ"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"ਪਿਛਲਾ ਦਿਖਾਓ"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"ਲਾਕ ਸਕ੍ਰੀਨ ਵਿਜੇਟ"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ਵਿਜੇਟ ਦੀ ਵਰਤੋਂ ਕਰ ਕੇ ਐਪ ਖੋਲ੍ਹਣ ਲਈ, ਤੁਹਾਨੂੰ ਇਹ ਪੁਸ਼ਟੀ ਕਰਨ ਦੀ ਲੋੜ ਪਵੇਗੀ ਕਿ ਇਹ ਤੁਸੀਂ ਹੀ ਹੋ। ਨਾਲ ਹੀ, ਇਹ ਵੀ ਧਿਆਨ ਵਿੱਚ ਰੱਖੋ ਕਿ ਕੋਈ ਵੀ ਉਨ੍ਹਾਂ ਨੂੰ ਦੇਖ ਸਕਦਾ ਹੈ, ਭਾਵੇਂ ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਲਾਕ ਹੋਵੇ। ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਕੁਝ ਵਿਜੇਟ ਤੁਹਾਡੀ ਲਾਕ ਸਕ੍ਰੀਨ ਲਈ ਨਾ ਬਣੇ ਹੋਣ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਇੱਥੇ ਸ਼ਾਮਲ ਕਰਨਾ ਅਸੁਰੱਖਿਅਤ ਹੋਵੇ।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ਸਮਝ ਲਿਆ"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਗੱਲਬਾਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ਵਿਚਾਰ"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"ਖਾਰਜ ਕਰੋ"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ਕਾਲ ਸੰਬੰਧੀ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ਇਹ ਸੂਚਨਾਵਾਂ ਦਾ ਗਰੁੱਪ ਇੱਥੇ ਸੰਰੂਪਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string> diff --git a/packages/SystemUI/res/values-pa/tiles_states_strings.xml b/packages/SystemUI/res/values-pa/tiles_states_strings.xml index 0f53e5d933df..eeb9a5beba7a 100644 --- a/packages/SystemUI/res/values-pa/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pa/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ਬੰਦ"</item> <item msgid="5908720590832378783">"ਚਾਲੂ"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index c0a283113568..d358b9f708b5 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -391,7 +391,7 @@ <string name="quick_settings_nfc_label" msgid="1054317416221168085">"Komunikacja NFC"</string> <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Komunikacja NFC jest wyłączona"</string> <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Komunikacja NFC jest włączona"</string> - <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Nagraj ekran"</string> + <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Nagrywanie ekranu"</string> <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Rozpocznij"</string> <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Zatrzymaj"</string> <string name="qs_record_issue_label" msgid="8166290137285529059">"Zarejestruj problem"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"odznacz widżet"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Zmniejsz wysokość"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Zwiększ wysokość"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Pokaż następny"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Pokaż poprzedni"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widżety na ekranie blokady"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Aby otworzyć aplikację za pomocą widżetu, musisz potwierdzić swoją tożsamość. Pamiętaj też, że każdy będzie mógł wyświetlić widżety nawet wtedy, gdy tablet będzie zablokowany. Niektóre widżety mogą nie być przeznaczone do umieszczenia na ekranie blokady i ich dodanie w tym miejscu może być niebezpieczne."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje funkcji rozmów"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Opinia"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Zamknij"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Nie pokazuj ponownie"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Powiadomień o połączeniach nie można modyfikować."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Tej grupy powiadomień nie można tu skonfigurować"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Składane urządzenie jest rozkładane"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Składane urządzenie jest obracane"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ekran przedni jest włączony"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Przesuń palcem, aby używać wewnętrznego ekranu"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"po zamknięciu"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"po otwarciu"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-pl/tiles_states_strings.xml b/packages/SystemUI/res/values-pl/tiles_states_strings.xml index c9eb500c3e9c..bc59a9057618 100644 --- a/packages/SystemUI/res/values-pl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pl/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Wyłączony"</item> <item msgid="5908720590832378783">"Włączony"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index c1a8ec4f5b0e..3a7d1f2db002 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -333,8 +333,8 @@ <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string> <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string> <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protetor de tela"</string> - <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmera"</string> - <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string> + <string name="quick_settings_camera_label" msgid="5612076679385269339">"Câmera"</string> + <string name="quick_settings_mic_label" msgid="8392773746295266375">"Microfone"</string> <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string> <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueada"</string> <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo de mídia"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"desmarcar widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Diminuir altura"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumentar altura"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Mostrar próximo"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Mostrar anterior"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da tela de bloqueio"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir um app usando um widget, você precisa confirmar sua identidade. E não se esqueça que qualquer pessoa pode ver os widgets, mesmo com o tablet bloqueado. Além disso, alguns apps não foram criados para a tela de bloqueio, é melhor manter a segurança."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendi"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Enviar feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Dispensar"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Não mostrar novamente"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamada."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar esse grupo de notificações aqui"</string> @@ -1524,7 +1531,7 @@ <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Automação residencial"</string> - <string name="home_controls_dream_description" msgid="4644150952104035789">"Controles de automação residencial no protetor de tela"</string> + <string name="home_controls_dream_description" msgid="4644150952104035789">"Controle de automação no protetor de tela"</string> <string name="volume_undo_action" msgid="5815519725211877114">"Desfazer"</string> <string name="back_edu_toast_content" msgid="4530314597378982956">"Se quiser voltar, deslize para a esquerda ou direita com três dedos no touchpad"</string> <string name="home_edu_toast_content" msgid="3381071147871955415">"Se quiser acessar a tela inicial, deslize para cima com três dedos no touchpad"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml index 9ddc41ca4b24..3e75cdd2bd09 100644 --- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Desativado"</item> <item msgid="5908720590832378783">"Ativado"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 36384bce6ba2..ff0ba3666efe 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -128,7 +128,7 @@ <string name="screenrecord_taps_label" msgid="1595690528298857649">"Mostrar toques no ecrã"</string> <string name="screenrecord_stop_label" msgid="72699670052087989">"Parar"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Partilhar"</string> - <string name="screenrecord_save_title" msgid="1886652605520893850">"Gravação de ecrã guardada."</string> + <string name="screenrecord_save_title" msgid="1886652605520893850">"Gravação de ecrã guardada"</string> <string name="screenrecord_save_text" msgid="3008973099800840163">"Toque para ver"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Erro ao guardar a gravação de ecrã"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Ocorreu um erro ao iniciar a gravação do ecrã."</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"desmarcar widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Diminuir altura"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumentar altura"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Mostrar próximo"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Mostrar anterior"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets do ecrã de bloqueio"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir uma app através de um widget, vai ter de validar a sua identidade. Além disso, tenha em atenção que qualquer pessoa pode ver os widgets, mesmo quando o tablet estiver bloqueado. Alguns widgets podem não se destinar ao ecrã de bloqueio e pode ser inseguro adicioná-los aqui."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta funcionalidades de conversa."</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Ignorar"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Não mostrar novamente"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamadas."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar este grupo de notificações aqui."</string> diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml index 5baa61c136dc..7e7e6734f57e 100644 --- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Desativado"</item> <item msgid="5908720590832378783">"Ativado"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index c1a8ec4f5b0e..3a7d1f2db002 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -333,8 +333,8 @@ <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string> <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string> <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Protetor de tela"</string> - <string name="quick_settings_camera_label" msgid="5612076679385269339">"Acesso à câmera"</string> - <string name="quick_settings_mic_label" msgid="8392773746295266375">"Acesso ao microfone"</string> + <string name="quick_settings_camera_label" msgid="5612076679385269339">"Câmera"</string> + <string name="quick_settings_mic_label" msgid="8392773746295266375">"Microfone"</string> <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Disponível"</string> <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Bloqueada"</string> <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Dispositivo de mídia"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"desmarcar widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Diminuir altura"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Aumentar altura"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Mostrar próximo"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Mostrar anterior"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgets da tela de bloqueio"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para abrir um app usando um widget, você precisa confirmar sua identidade. E não se esqueça que qualquer pessoa pode ver os widgets, mesmo com o tablet bloqueado. Além disso, alguns apps não foram criados para a tela de bloqueio, é melhor manter a segurança."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Entendi"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com recursos de conversa"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Enviar feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Dispensar"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Não mostrar novamente"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Não é possível modificar as notificações de chamada."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Não é possível configurar esse grupo de notificações aqui"</string> @@ -1524,7 +1531,7 @@ <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz de fundo do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nível %1$d de %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Automação residencial"</string> - <string name="home_controls_dream_description" msgid="4644150952104035789">"Controles de automação residencial no protetor de tela"</string> + <string name="home_controls_dream_description" msgid="4644150952104035789">"Controle de automação no protetor de tela"</string> <string name="volume_undo_action" msgid="5815519725211877114">"Desfazer"</string> <string name="back_edu_toast_content" msgid="4530314597378982956">"Se quiser voltar, deslize para a esquerda ou direita com três dedos no touchpad"</string> <string name="home_edu_toast_content" msgid="3381071147871955415">"Se quiser acessar a tela inicial, deslize para cima com três dedos no touchpad"</string> diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml index 9ddc41ca4b24..3e75cdd2bd09 100644 --- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Desativado"</item> <item msgid="5908720590832378783">"Ativado"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index beb3c1166684..2417c840a2cd 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"deselectează widgetul"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Redu înălțimea"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Crește înălțimea"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Afișează elementul următor"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Afișează elementul anterior"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgeturi pe ecranul de blocare"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Pentru a deschide o aplicație folosind un widget, va trebui să-ți confirmi identitatea. În plus, reține că oricine poate să vadă widgeturile, chiar dacă tableta este blocată. Este posibil ca unele widgeturi să nu fi fost create pentru ecranul de blocare și poate fi nesigur să le adaugi aici."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă funcții pentru conversații"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Închide"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Nu mai afișa"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Notificările pentru apeluri nu pot fi modificate."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Acest grup de notificări nu poate fi configurat aici"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Dispozitiv pliabil care este desfăcut"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Dispozitiv pliabil care este întors"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ecranul frontal este activat"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Glisează pentru a folosi ecranul interior"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"închis"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"deschis"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-ro/tiles_states_strings.xml b/packages/SystemUI/res/values-ro/tiles_states_strings.xml index 528b112c72a6..6dcb0d3c1635 100644 --- a/packages/SystemUI/res/values-ro/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ro/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Dezactivat"</item> <item msgid="5908720590832378783">"Activat"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index e3f852c5bcc3..f6968d531535 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -129,7 +129,7 @@ <string name="screenrecord_stop_label" msgid="72699670052087989">"Остановить"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"Поделиться"</string> <string name="screenrecord_save_title" msgid="1886652605520893850">"Видео с экрана сохранено"</string> - <string name="screenrecord_save_text" msgid="3008973099800840163">"Нажмите, чтобы посмотреть."</string> + <string name="screenrecord_save_text" msgid="3008973099800840163">"Нажмите, чтобы посмотреть"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"Не удалось сохранить запись видео с экрана."</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"Не удалось начать запись видео с экрана."</string> <string name="screenrecord_stop_dialog_title" msgid="8716193661764511095">"Остановить запись?"</string> @@ -162,7 +162,7 @@ <string name="issuerecord_ongoing_screen_only" msgid="6248206059935015722">"Записываем проблему на видео"</string> <string name="issuerecord_share_label" msgid="3992657993619876199">"Поделиться"</string> <string name="issuerecord_save_title" msgid="4161043023696751591">"Запись сохранена."</string> - <string name="issuerecord_save_text" msgid="1205985304551521495">"Нажмите, чтобы посмотреть."</string> + <string name="issuerecord_save_text" msgid="1205985304551521495">"Нажмите, чтобы посмотреть"</string> <string name="issuerecord_save_error" msgid="6913040083446722726">"Не удалось сохранить запись."</string> <string name="issuerecord_start_error" msgid="3402782952722871190">"Не удалось начать запись."</string> <string name="immersive_cling_title" msgid="8372056499315585941">"Полноэкранный режим"</string> @@ -335,7 +335,7 @@ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Заставка"</string> <string name="quick_settings_camera_label" msgid="5612076679385269339">"Доступ к камере"</string> <string name="quick_settings_mic_label" msgid="8392773746295266375">"Доступ к микрофону"</string> - <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Есть"</string> + <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Разрешен"</string> <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Заблокировано"</string> <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Режим медиа"</string> <string name="quick_settings_user_title" msgid="8673045967216204537">"Пользователь"</string> @@ -381,7 +381,7 @@ <string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Включить в <xliff:g id="TIME">%s</xliff:g>"</string> <string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"До <xliff:g id="TIME">%s</xliff:g>"</string> <string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Тёмная тема"</string> - <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Режим энергосбер."</string> + <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Энергосбережение"</string> <string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Вкл. на закате"</string> <string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"До рассвета"</string> <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Включить в <xliff:g id="TIME">%s</xliff:g>"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"отменить выбор виджета"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Уменьшить высоту"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Увеличить высоту"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Показать следующий"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Показать предыдущий"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виджеты на заблокированном экране"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Чтобы открыть приложение, используя виджет, вам нужно будет подтвердить свою личность. Обратите внимание, что виджеты видны всем, даже если планшет заблокирован. Некоторые виджеты не предназначены для использования на заблокированном экране. Добавлять их туда может быть небезопасно."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ОК"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает функции разговоров."</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Оставить отзыв"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Закрыть"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Больше не показывать"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Уведомления о звонках нельзя изменить."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Эту группу уведомлений нельзя настроить здесь."</string> diff --git a/packages/SystemUI/res/values-ru/tiles_states_strings.xml b/packages/SystemUI/res/values-ru/tiles_states_strings.xml index 43d3e2ac31ed..e7ff74d61ce3 100644 --- a/packages/SystemUI/res/values-ru/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ru/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Отключено"</item> <item msgid="5908720590832378783">"Включено"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 9ff67479aed2..eb816b804c68 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"විජට් නොතෝරන්න"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"උස අඩු කරන්න"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"උස වැඩි කරන්න"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"මීළග පෙන්වන්න"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"පෙර එක පෙන්වන්න"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"අගුළු තිර විජට්"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"විජට් එකක් භාවිතයෙන් යෙදුමක් විවෘත කිරීමට, ඔබට ඒ ඔබ බව සත්යාපනය කිරීමට අවශ්ය වනු ඇත. එසේම, ඔබේ ටැබ්ලටය අගුළු දමා ඇති විට පවා ඕනෑම කෙනෙකුට ඒවා බැලිය හැකි බව මතක තබා ගන්න. සමහර විජට් ඔබේ අගුළු තිරය සඳහා අදහස් කර නොතිබිය හැකි අතර මෙහි එක් කිරීමට අනාරක්ෂිත විය හැක."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"තේරුණා"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාද විශේෂාංගවලට සහාය නොදක්වයි"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ප්රතිපෝෂණය"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"අස් කරන්න"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"නැවත නොපෙන්වන්න"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"මෙම දැනුම්දීම් වෙනස් කළ නොහැක."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"ඇමතුම් දැනුම්දීම් වෙනස් කළ නොහැකිය."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"මෙම දැනුම්දීම් සමූහය මෙහි වින්යාස කළ නොහැක"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"දිග හැරෙමින් පවතින නැමිය හැකි උපාංගය"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"වටා පෙරළෙමින් තිබෙන නැමිය හැකි උපාංගය"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ඉදිරිපස තිරය ක්රියාත්මකයි"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"අභ්යන්තර තිරය භාවිතා කිරීමට ස්ලයිඩ් කරන්න"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"නැවූ"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"නොනැවූ"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-si/tiles_states_strings.xml b/packages/SystemUI/res/values-si/tiles_states_strings.xml index 91280e1e00bd..710e9aa1893d 100644 --- a/packages/SystemUI/res/values-si/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-si/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ක්රියාවිරහිතයි"</item> <item msgid="5908720590832378783">"ක්රියාත්මකයි"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index a42eb1e6c35e..fcb281d3bf59 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -354,7 +354,7 @@ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzia farieb"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Úprava farieb"</string> <string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"Veľkosť písma"</string> - <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Spravovať použ."</string> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Spravovať používateľov"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zavrieť"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Pripojené"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"zrušiť výber miniaplikácie"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Znížiť výšku"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Zväčšiť výšku"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Zobraziť ďalší"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Zobraziť predchádzajúci"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Miniaplikácie na uzamknutej obrazovke"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ak chcete otvoriť aplikáciu pomocou miniaplikácie, budete musieť overiť svoju totožnosť. Pamätajte, že si miniaplikáciu môže pozrieť ktokoľvek, aj keď máte tablet uzamknutý. Niektoré miniaplikácie možno nie sú určené pre uzamknutú obrazovku a ich pridanie tu môže byť nebezpečné."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Dobre"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje funkcie konverzácie"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Spätná väzba"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Zavrieť"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Nabudúce nezobrazovať"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Upozornenia na hovory sa nedajú upraviť."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Túto skupinu upozornení nejde na tomto mieste konfigurovať"</string> @@ -1349,7 +1356,7 @@ <string name="clipboard_image_preview" msgid="2156475174343538128">"Ukážka obrázka"</string> <string name="clipboard_edit" msgid="4500155216174011640">"upraviť"</string> <string name="add" msgid="81036585205287996">"Pridať"</string> - <string name="manage_users" msgid="1823875311934643849">"Spravovať použ."</string> + <string name="manage_users" msgid="1823875311934643849">"Spravovať používateľov"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Toto upozornenie nepodporuje presun na rozdelenú obrazovku"</string> <string name="dream_overlay_location_active" msgid="6484763493158166618">"Aktívne miesto"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi nie je k dispozícii"</string> @@ -1524,7 +1531,7 @@ <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvietenie klávesnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. úroveň z %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládanie domácnosti"</string> - <string name="home_controls_dream_description" msgid="4644150952104035789">"Rýchly prístup k ovládaniu domácnosti z šetriča obrazovky"</string> + <string name="home_controls_dream_description" msgid="4644150952104035789">"Rýchle ovládanie domácnosti z šetriča obrazovky"</string> <string name="volume_undo_action" msgid="5815519725211877114">"Vrátiť späť"</string> <string name="back_edu_toast_content" msgid="4530314597378982956">"Ak chcete prejsť späť, potiahnite po touchpade troma prstami doľava alebo doprava"</string> <string name="home_edu_toast_content" msgid="3381071147871955415">"Ak sa chcete vrátiť na plochu, potiahnite po touchpade troma prstami nahor."</string> diff --git a/packages/SystemUI/res/values-sk/tiles_states_strings.xml b/packages/SystemUI/res/values-sk/tiles_states_strings.xml index 0b0b89483188..83235060a612 100644 --- a/packages/SystemUI/res/values-sk/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sk/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Vypnuté"</item> <item msgid="5908720590832378783">"Zapnuté"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index c0e751b82c9f..e99906546861 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"preklic izbire pripomočka"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Zmanjšanje višine"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Povečanje višine"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Prikaz naslednjega"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Prikaz prejšnjega"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Pripomočki na zaklenjenem zaslonu"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Če želite aplikacijo odpreti s pripomočkom, morate potrditi, da ste to vi. Upoštevajte tudi, da si jih lahko ogledajo vsi, tudi ko je tablični računalnik zaklenjen. Nekateri pripomočki morda niso predvideni za uporabo na zaklenjenem zaslonu, zato jih tukaj morda ni varno dodati."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Razumem"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira pogovornih funkcij."</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Povratne informacije"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Opusti"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Tega ne prikaži več"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Obvestil o klicih ni mogoče spreminjati."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Te skupine obvestil ni mogoče konfigurirati tukaj"</string> diff --git a/packages/SystemUI/res/values-sl/tiles_states_strings.xml b/packages/SystemUI/res/values-sl/tiles_states_strings.xml index f9ccbb1fde86..d644038f9a8d 100644 --- a/packages/SystemUI/res/values-sl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sl/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Izklopljeno"</item> <item msgid="5908720590832378783">"Vklopljeno"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 06cefd9c7734..7e2b6980b61c 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"anulo zgjedhjen e miniaplikacionit"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Zvogëlo lartësinë"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Rrit lartësinë"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Shfaq tjetrin"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Shfaq të mëparshmin"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Miniaplikacionet në ekranin e kyçjes"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Për të hapur një aplikacion duke përdorur një miniaplikacion, do të duhet të verifikosh që je ti. Ki parasysh gjithashtu që çdo person mund t\'i shikojë, edhe kur tableti yt është i kyçur. Disa miniaplikacione mund të mos jenë planifikuar për ekranin tënd të kyçjes dhe mund të mos jetë e sigurt t\'i shtosh këtu."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"E kuptova"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk mbështet veçoritë e bisedës"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Koment"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Hiq"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Mos e shfaq më"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Njoftimet e telefonatave nuk mund të modifikohen."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ky grup njoftimesh nuk mund të konfigurohet këtu"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Pajisja e palosshme duke u hapur"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Pajisja e palosshme duke u rrotulluar"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ekrani i përparmë është aktivizuar"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Rrëshqit për të përdorur ekranin e brendshëm"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"palosur"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"shpalosur"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-sq/tiles_states_strings.xml b/packages/SystemUI/res/values-sq/tiles_states_strings.xml index 1ab4f01c56e2..1b1a62f203aa 100644 --- a/packages/SystemUI/res/values-sq/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sq/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Joaktive"</item> <item msgid="5908720590832378783">"Aktive"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 3977058725a2..1e44e0c2799d 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"поништи избор виџета"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Смањи висину"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Повећај висину"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Прикажите следеће"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Прикажите претходно"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Виџети за закључани екран"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Да бисте отворили апликацију која користи виџет, треба да потврдите да сте то ви. Имајте у виду да свако може да га види, чак и када је таблет закључан. Неки виџети можда нису намењени за закључани екран и можда није безбедно да их тамо додате."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Важи"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава функције конверзације"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Повратне информације"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Одбаци"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Не приказуј поново"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Обавештења о позивима не могу да се мењају."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ова група обавештења не може да се конфигурише овде"</string> @@ -1370,7 +1377,7 @@ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Промените излаз"</string> <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Непознато"</string> <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"с:мин"</string> - <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"ч:мин"</string> + <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string> <string name="log_access_confirmation_title" msgid="4843557604739943395">"Желите да дозволите да <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> приступа свим евиденцијама уређаја?"</string> <string name="log_access_confirmation_allow" msgid="752147861593202968">"Дозволи једнократан приступ"</string> <string name="log_access_confirmation_deny" msgid="2389461495803585795">"Не дозволи"</string> diff --git a/packages/SystemUI/res/values-sr/tiles_states_strings.xml b/packages/SystemUI/res/values-sr/tiles_states_strings.xml index ec5f10f63e1a..e1bd7b1740da 100644 --- a/packages/SystemUI/res/values-sr/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sr/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Искључено"</item> <item msgid="5908720590832378783">"Укључено"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 7051a2a92aa7..d613922318db 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"avmarkera widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Minska höjden"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Öka höjden"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Visa nästa"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Visa föregående"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Widgetar för låsskärm"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Du måste verifiera din identitet innan du öppnar en app med en widget. Tänk också på att alla kan se dem, även när surfplattan är låst. Vissa widgetar kanske inte är avsedda för låsskärmen och det kan vara osäkert att lägga till dem här."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsfunktioner"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Stäng"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Visa inte igen"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Det går inte att ändra samtalsaviseringarna."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Den här aviseringsgruppen kan inte konfigureras här"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"En vikbar enhet viks upp"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"En vikbar enhet vänds"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Den främre skärmen har aktiverats"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Dra för att använda den inre skärmen"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"hopvikt"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"uppvikt"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-sv/tiles_states_strings.xml b/packages/SystemUI/res/values-sv/tiles_states_strings.xml index e9da8053759d..37d757e93f49 100644 --- a/packages/SystemUI/res/values-sv/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sv/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Av"</item> <item msgid="5908720590832378783">"På"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 2ead01a37907..33d8511edf96 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -335,7 +335,7 @@ <string name="quick_settings_screensaver_label" msgid="1495003469366524120">"Taswira ya skrini"</string> <string name="quick_settings_camera_label" msgid="5612076679385269339">"Ufikiaji wa kamera"</string> <string name="quick_settings_mic_label" msgid="8392773746295266375">"Ufikiaji wa maikrofoni"</string> - <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Unapatikana"</string> + <string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Inapatikana"</string> <string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Umezuiwa"</string> <string name="quick_settings_media_device_label" msgid="8034019242363789941">"Kifaa cha faili"</string> <string name="quick_settings_user_title" msgid="8673045967216204537">"Mtumiaji"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"acha kuchagua wijeti"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Punguza urefu"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Ongeza urefu"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Onyesha inayofuata"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Onyesha iliyotangulia"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Wijeti zinazoonekana kwenye skrini iliyofungwa"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Utahitaji kuthibitisha kuwa ni wewe ili ufungue programu ukitumia wijeti. Pia, kumbuka kuwa mtu yeyote anaweza kuziona, hata kishikwambi chako kikiwa kimefungwa. Huenda baadhi ya wijeti hazikukusudiwa kutumika kwenye skrini yako iliyofungwa na huenda si salama kuziweka hapa."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Nimeelewa"</string> @@ -573,7 +575,7 @@ <string name="media_projection_entry_app_permission_dialog_warning_single_app" msgid="7094417930857938876">"Unaporuhusu ufikiaji wa programu, chochote kinachoonyeshwa au kuchezwa katika programu hiyo kitaonekana kwa <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>. Kwa hivyo kuwa mwangalifu na vitu kama vile manenosiri, maelezo ya malipo, ujumbe, picha, sauti na video."</string> <string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Ruhusu ufikiaji wa skrini"</string> <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> imezima chaguo hili"</string> - <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Kuchagua programu utakayoruhusu ifikiwe"</string> + <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Chagua programu utakayoruhusu ifikiwe"</string> <string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Ungependa kutuma maudhui yaliyo katika skrini yako?"</string> <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Tuma maudhui ya programu moja"</string> <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Tuma maudhui katika skrini nzima"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii vipengele vya mazungumzo"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Maoni"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Ondoa"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Usionyeshe tena"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Arifa za simu haziwezi kubadilishwa."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Kikundi hiki cha arifa hakiwezi kuwekewa mipangilio hapa"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Kifaa kinachokunjwa kikikunjuliwa"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Kifaa kinachokunjwa kikigeuzwa"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Umewasha skrini ya mbele"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Telezesha kidole ili utumie skrini ya ndani"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kimekunjwa"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kimefunguliwa"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml index 702af458652a..fae42c3980b0 100644 --- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml @@ -64,12 +64,12 @@ <string-array name="tile_states_rotation"> <item msgid="4578491772376121579">"Hakipatikani"</item> <item msgid="5776427577477729185">"Kimezimwa"</item> - <item msgid="7105052717007227415">"Kimewashwa"</item> + <item msgid="7105052717007227415">"Imewashwa"</item> </string-array> <string-array name="tile_states_bt"> <item msgid="5330252067413512277">"Hakipatikani"</item> <item msgid="5315121904534729843">"Kimezimwa"</item> - <item msgid="503679232285959074">"Kimewashwa"</item> + <item msgid="503679232285959074">"Imewashwa"</item> </string-array> <string-array name="tile_states_airplane"> <item msgid="1985366811411407764">"Hakipatikani"</item> @@ -93,7 +93,7 @@ </string-array> <string-array name="tile_states_inversion"> <item msgid="3638187931191394628">"Hakipatikani"</item> - <item msgid="9103697205127645916">"Kimezimwa"</item> + <item msgid="9103697205127645916">"Umezimwa"</item> <item msgid="8067744885820618230">"Kimewashwa"</item> </string-array> <string-array name="tile_states_saver"> @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Limezimwa"</item> <item msgid="5908720590832378783">"Limewashwa"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index b37350cc3b82..aa312c713a5d 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"விட்ஜெட்டைத் தேர்வுநீக்கும்"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"உயரத்தைக் குறைக்கும்"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"உயரத்தை அதிகரிக்கும்"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"அடுத்ததைக் காட்டும்"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"முந்தையதைக் காட்டும்"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"பூட்டுத் திரை விட்ஜெட்கள்"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"விட்ஜெட்டைப் பயன்படுத்தி ஆப்ஸைத் திறக்க, அது நீங்கள்தான் என்பதை உறுதிசெய்ய வேண்டும். அத்துடன், உங்கள் டேப்லெட் பூட்டப்பட்டிருந்தாலும்கூட அவற்றை யார் வேண்டுமானாலும் பார்க்கலாம் என்பதை நினைவில்கொள்ளுங்கள். சில விட்ஜெட்கள் உங்கள் பூட்டுத் திரைக்காக உருவாக்கப்பட்டவை அல்ல என்பதையும் அவற்றை இங்கே சேர்ப்பது பாதுகாப்பற்றதாக இருக்கக்கூடும் என்பதையும் நினைவில்கொள்ளுங்கள்."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"சரி"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"உரையாடல் அம்சங்களை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"கருத்து"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"மூடுக"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"மீண்டும் காட்டாதே"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"அழைப்பு அறிவிப்புகளை மாற்ற முடியாது."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"மடக்கத்தக்க சாதனம் திறக்கப்படுகிறது"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"மடக்கத்தக்க சாதனம் ஃபிளிப் செய்யப்பட்டு திருப்பப்படுகிறது"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"முன்பக்கத் திரை இயக்கப்பட்டுள்ளது"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"உட்புறத் திரையைப் பயன்படுத்த ஸ்லைடு செய்யுங்கள்"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"மடக்கப்பட்டது"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"விரிக்கப்பட்டது"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-ta/tiles_states_strings.xml b/packages/SystemUI/res/values-ta/tiles_states_strings.xml index 17cc570f6b0d..b09b17f40cd3 100644 --- a/packages/SystemUI/res/values-ta/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ta/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"முடக்கப்பட்டுள்ளது"</item> <item msgid="5908720590832378783">"இயக்கப்பட்டுள்ளது"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index f64c737d8236..fc5361b54628 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"విడ్జెట్ ఎంపిక రద్దు చేయండి"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ఎత్తును తగ్గించండి"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"ఎత్తును పెంచండి"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"తర్వాతది చూడండి"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"మునుపటి దాన్ని చూడండి"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"లాక్ స్క్రీన్ విడ్జెట్లు"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"విడ్జెట్ను ఉపయోగించి యాప్ను తెరవడానికి, ఇది మీరేనని వెరిఫై చేయాల్సి ఉంటుంది. అలాగే, మీ టాబ్లెట్ లాక్ చేసి ఉన్నప్పటికీ, ఎవరైనా వాటిని చూడగలరని గుర్తుంచుకోండి. కొన్ని విడ్జెట్లు మీ లాక్ స్క్రీన్కు తగినవి కాకపోవచ్చు, వాటిని ఇక్కడ జోడించడం సురక్షితం కాకపోవచ్చు."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"అర్థమైంది"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> సంభాషణ ఫీచర్లను సపోర్ట్ చేయదు"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ఫీడ్బ్యాక్"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"విస్మరించండి"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"మళ్లీ చూపవద్దు"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్లను ఎడిట్ చేయడం వీలుపడదు."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"కాల్ నోటిఫికేషన్లను ఎడిట్ చేయడం సాధ్యం కాదు."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"ఈ నోటిఫికేషన్ల గ్రూప్ను ఇక్కడ కాన్ఫిగర్ చేయలేము"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"మడవగల పరికరం విప్పబడుతోంది"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"మడవగల పరికరం చుట్టూ తిప్పబడుతోంది"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"ముందు వైపు స్క్రీన్ ఆన్ అయింది"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"లోపలి స్క్రీన్ను ఉపయోగించడానికి స్లయిడ్ చేయండి"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"మడిచే సదుపాయం గల పరికరం"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"మడిచే సదుపాయం లేని పరికరం"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-te/tiles_states_strings.xml b/packages/SystemUI/res/values-te/tiles_states_strings.xml index 8a0ab4848f60..7562aaec0118 100644 --- a/packages/SystemUI/res/values-te/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-te/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ఆఫ్లో ఉంది"</item> <item msgid="5908720590832378783">"ఆన్లో ఉంది"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 316aab0270ff..873635d6add5 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ยกเลิกการเลือกวิดเจ็ต"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"ลดความสูง"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"เพิ่มความสูง"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"แสดงมีเดียเพลเยอร์ถัดไป"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"แสดงมีเดียเพลเยอร์ก่อนหน้า"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"วิดเจ็ตในหน้าจอล็อก"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"หากต้องการเปิดแอปโดยใช้วิดเจ็ต คุณจะต้องยืนยันตัวตนของคุณ นอกจากนี้ โปรดทราบว่าผู้อื่นจะดูวิดเจ็ตเหล่านี้ได้แม้ว่าแท็บเล็ตจะล็อกอยู่ก็ตาม วิดเจ็ตบางอย่างอาจไม่ได้มีไว้สำหรับหน้าจอล็อกของคุณ และอาจไม่ปลอดภัยที่จะเพิ่มที่นี่"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"รับทราบ"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับฟีเจอร์การสนทนา"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"ความคิดเห็น"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"ปิด"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"ไม่ต้องแสดงอีก"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"แก้ไขการแจ้งเตือนเหล่านี้ไม่ได้"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"แก้ไขการแจ้งเตือนสายเรียกเข้าไม่ได้"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"การแจ้งเตือนกลุ่มนี้กำหนดค่าที่นี่ไม่ได้"</string> diff --git a/packages/SystemUI/res/values-th/tiles_states_strings.xml b/packages/SystemUI/res/values-th/tiles_states_strings.xml index 4db59c0677c4..6d360367fac7 100644 --- a/packages/SystemUI/res/values-th/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-th/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"ปิด"</item> <item msgid="5908720590832378783">"เปิด"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 04dc6c7c7680..e6aa410c269b 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"i-unselect ang widget"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Bawasan ang taas"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Dagdagan ang taas"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Ipakita ang susunod"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Ipakita ang mga nakaraan"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Mga widget ng lock screen"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Para magbukas ng app gamit ang isang widget, kakailanganin mong i-verify na ikaw iyan. Bukod pa rito, tandaang puwedeng tingnan ng kahit na sino ang mga ito, kahit na naka-lock ang iyong tablet. Posibleng hindi para sa iyong lock screen ang ilang widget at posibleng hindi ligtas ang mga ito na idagdag dito."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga feature ng pag-uusap"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Feedback"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"I-dismiss"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Huwag nang ipakita ulit"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Hindi puwedeng baguhin ang mga notification na ito."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Hindi mabago ang mga notification ng tawag."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Hindi mako-configure dito ang pangkat na ito ng mga notification"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Ina-unfold na foldable na device"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Fini-flip na foldable na device"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Na-on ang screen sa harap"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"I-slide para gamitin ang inner screen"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"naka-fold"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"hindi naka-fold"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-tl/tiles_states_strings.xml b/packages/SystemUI/res/values-tl/tiles_states_strings.xml index 4832d1d1b0de..112c0bf11e73 100644 --- a/packages/SystemUI/res/values-tl/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-tl/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Naka-off"</item> <item msgid="5908720590832378783">"Naka-on"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index f4a2c9260398..05fc1f23a24c 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"widget\'ın seçimini kaldırın"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Yüksekliği azalt"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Yüksekliği artır"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Sonrakini göster"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Öncekini göster"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Kilit ekranı widget\'ları"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Widget kullanarak bir uygulamayı açmak için kimliğinizi doğrulamanız gerekir. Ayrıca, tabletiniz kilitliyken bile widget\'ların herkes tarafından görüntülenebileceğini unutmayın. Bazı widget\'lar kilit ekranınız için tasarlanmamış olabileceğinden buraya eklenmeleri güvenli olmayabilir."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Anladım"</string> @@ -542,7 +544,7 @@ <string name="hub_onboarding_bottom_sheet_text" msgid="8589816797970240544">"Cihazınız şarj olurken en sevdiğiniz widget\'lara ve ekran koruyuculara erişin."</string> <string name="hub_onboarding_bottom_sheet_action_button" msgid="6161983690157872829">"Başlayalım"</string> <string name="glanceable_hub_to_dream_button_tooltip" msgid="9018287673822335829">"Cihazınız şarj olurken en sevdiğiniz ekran koruyucuları gösterin"</string> - <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string> + <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştir"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Misafir kullanıcı, tekrar hoşgeldiniz"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>, sohbet özelliklerini desteklemiyor"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Geri bildirim"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Kapat"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Tekrar gösterme"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Arama bildirimleri değiştirilemez."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Bu bildirim grubu burada yapılandırılamaz"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Katlanabilir cihaz açılıyor"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Katlanabilir cihaz döndürülüyor"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Ön ekran açıldı"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"İç taraftaki ekranı kullanmak için kaydırın"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"katlanmış"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"katlanmamış"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-tr/tiles_states_strings.xml b/packages/SystemUI/res/values-tr/tiles_states_strings.xml index 1c0c110baab1..f3c51c093c4a 100644 --- a/packages/SystemUI/res/values-tr/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-tr/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Kapalı"</item> <item msgid="5908720590832378783">"Açık"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 7dab3db1d310..0b0d6dc15c62 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"скасувати вибір віджета"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Зменшити висоту"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Збільшити висоту"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Показати наступний"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Показати попередній"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Віджети для заблокованого екрана"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Щоб відкрити додаток за допомогою віджета, вам потрібно буде підтвердити особу. Пам’ятайте також, що бачити віджети можуть усі, навіть коли планшет заблоковано. Можливо, деякі віджети не призначені для заблокованого екрана, і додавати їх на нього може бути небезпечно."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує функції розмов"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Надіслати відгук"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Закрити"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Більше не показувати"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Сповіщення про виклик не можна змінити."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Цю групу сповіщень не можна налаштувати тут"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Розкладний пристрій у розкладеному стані"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Розкладний пристрій обертається"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Передній екран увімкнено"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Проведіть пальцем, щоб використовувати внутрішній екран"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"складений"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"розкладений"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-uk/tiles_states_strings.xml b/packages/SystemUI/res/values-uk/tiles_states_strings.xml index 656ccd439244..4fac740d1693 100644 --- a/packages/SystemUI/res/values-uk/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-uk/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Вимкнено"</item> <item msgid="5908720590832378783">"Увімкнено"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 646072122204..ab4dd7738030 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"ویجیٹ غیر منتخب کریں"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"اونچائی کم کریں"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"اونچائی بڑھائیں"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"اگلا دکھائیں"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"سابقہ دکھائیں"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"مقفل اسکرین کے ویجیٹس"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ویجیٹ کے ذریعے ایپ کھولنے کے لیے آپ کو تصدیق کرنی ہوگی کہ یہ آپ ہی ہیں۔ نیز، ذہن میں رکھیں کہ کوئی بھی انہیں دیکھ سکتا ہے، یہاں تک کہ جب آپ کا ٹیبلیٹ مقفل ہو۔ ہو سکتا ہے کچھ ویجٹس آپ کی لاک اسکرین کے لیے نہ بنائے گئے ہوں اور یہاں شامل کرنا غیر محفوظ ہو سکتا ہے۔"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"سمجھ آ گئی"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ گفتگو کی خصوصیات کو سپورٹ نہیں کرتی ہے"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"تاثرات"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"برخاست کریں"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"دوبارہ نہ دکھائیں"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"کال کی اطلاعات میں ترمیم نہیں کی جا سکتی۔"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"اطلاعات کے اس گروپ کو یہاں کنفیگر نہیں کیا جا سکتا"</string> diff --git a/packages/SystemUI/res/values-ur/tiles_states_strings.xml b/packages/SystemUI/res/values-ur/tiles_states_strings.xml index 4aa490d927b1..06e213b36a99 100644 --- a/packages/SystemUI/res/values-ur/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-ur/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"آف"</item> <item msgid="5908720590832378783">"آن"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 6bcd9d6c4c1c..55caf257c255 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -60,12 +60,12 @@ <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Tilni almashtirish"</string> <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Joriy tilni qoldirish"</string> <string name="share_wifi_button_text" msgid="1285273973812029240">"Wi‑Fi ulashuv"</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Wi-Fi orqali debagging uchun ruxsat berilsinmi?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Wi-Fi orqali debaging uchun ruxsat berilsinmi?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Tarmoq nomi (SSID):\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nWi‑Fi Manzil (BSSID):\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Bu tarmoqda doim ruxsat etilsin"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Ruxsat"</string> - <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Wi-Fi orqali debagging taqiqlandi"</string> - <string name="wifi_debugging_secondary_user_message" msgid="9085779370142222881">"Ayni paytda ushbu qurilmaga oʻz hisobi bilan kirgan foydalanuvchi Wi-Fi orqali debagging funksiyasini yoqa olmaydi. Bu funksiyadan foydalanish uchun administrator profiliga oʻting."</string> + <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Wi-Fi orqali debaging taqiqlandi"</string> + <string name="wifi_debugging_secondary_user_message" msgid="9085779370142222881">"Ayni paytda ushbu qurilmaga oʻz hisobi bilan kirgan foydalanuvchi Wi-Fi orqali debaging funksiyasini yoqa olmaydi. Bu funksiyadan foydalanish uchun administrator profiliga oʻting."</string> <string name="usb_contaminant_title" msgid="894052515034594113">"USB port faolsizlashtirildi"</string> <string name="usb_contaminant_message" msgid="7730476585174719805">"Qurilmangizni suyuqlik va turli parchalardan himoya qilish uchun USB port faolsizlashtiriladi va hech qanday aksessuarni aniqlay olmaydi.\n\nUSB portdan xavfsiz foydalanish mumkin boʻlganda, sizga xabar beriladi."</string> <string name="usb_port_enabled" msgid="531823867664717018">"Quvvatlash moslamalari va aksessuarlarni aniqlash uchun USB port yoqildi"</string> @@ -354,7 +354,7 @@ <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ranglarni akslantirish"</string> <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ranglarni tuzatish"</string> <string name="quick_settings_font_scaling_label" msgid="5289001009876936768">"Shrift hajmi"</string> - <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Foyd-ni boshqarish"</string> + <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Foydalanuvchilarni boshqarish"</string> <string name="quick_settings_done" msgid="2163641301648855793">"Tayyor"</string> <string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Yopish"</string> <string name="quick_settings_connected" msgid="3873605509184830379">"Ulangan"</string> @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"vidjetni bekor qilish"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Balandligini kichraytirish"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Balandligini oshirish"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Keyingisi"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Avvalgisi"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Ekran qulfi vidjetlari"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ilovani vidjet orqali ochish uchun shaxsingizni tasdiqlashingiz kerak. Shuningdek, planshet qulflanganda ham bu axborotlar hammaga koʻrinishini unutmang. Ayrim vidjetlar ekran qulfiga moslanmagan va ularni bu yerda chiqarish xavfli boʻlishi mumkin."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat funksiyalari ishlamaydi"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Fikr-mulohaza"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Yopish"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Boshqa chiqmasin"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Chaqiruv bildirishnomalarini tahrirlash imkonsiz."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string> @@ -1349,7 +1356,7 @@ <string name="clipboard_image_preview" msgid="2156475174343538128">"Rasmga razm solish"</string> <string name="clipboard_edit" msgid="4500155216174011640">"tahrir"</string> <string name="add" msgid="81036585205287996">"Kiritish"</string> - <string name="manage_users" msgid="1823875311934643849">"Foyd-ni boshqarish"</string> + <string name="manage_users" msgid="1823875311934643849">"Foydalanuvchilarni boshqarish"</string> <string name="drag_split_not_supported" msgid="7173481676120546121">"Bu bildirishnoma ikkiga ajratilgan ekranda ishlamaydi."</string> <string name="dream_overlay_location_active" msgid="6484763493158166618">"Joylashuv faol"</string> <string name="dream_overlay_status_bar_wifi_off" msgid="4497069245055003582">"Wi‑Fi ishlamayapti"</string> @@ -1394,10 +1401,9 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Buklanadigan qurilma ochilmoqda"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Buklanadigan qurilma aylantirilmoqda"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Old ekran yoqildi"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Ichki ekranni ishlatish uchun surish"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"buklangan"</string> - <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"buklanmagan"</string> + <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"yoyib ochilgan"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> <string name="stylus_battery_low_percentage" msgid="2564243323894629626">"Stilus batareyasi: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string> <string name="stylus_battery_low_subtitle" msgid="3583843128908823273">"Stilusni quvvat manbaiga ulang"</string> diff --git a/packages/SystemUI/res/values-uz/tiles_states_strings.xml b/packages/SystemUI/res/values-uz/tiles_states_strings.xml index 1c32e9fbd53b..f636bc61bb99 100644 --- a/packages/SystemUI/res/values-uz/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-uz/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Yoqilmagan"</item> <item msgid="5908720590832378783">"Yoniq"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index a9f24ed1da78..35fe2f2428d4 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"bỏ chọn tiện ích"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Giảm chiều cao"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Tăng chiều cao"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Hiện trình phát nội dung nghe nhìn tiếp theo"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Hiện trình phát nội dung nghe nhìn trước"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Tiện ích trên màn hình khoá"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Để dùng tiện ích mở một ứng dụng, bạn cần xác minh danh tính của mình. Ngoài ra, hãy lưu ý rằng bất kỳ ai cũng có thể xem các tiện ích này, ngay cả khi máy tính bảng của bạn được khoá. Một số tiện ích có thể không dành cho màn hình khoá và không an toàn khi thêm vào đây."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Tôi hiểu"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ các tính năng trò chuyện"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Phản hồi"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Đóng"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Không hiện lại"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Không thể sửa đổi các thông báo cuộc gọi."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Không thể định cấu hình nhóm thông báo này tại đây"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Thiết bị có thể gập lại đang được mở ra"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Thiết bị có thể gập lại đang được lật ngược"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Đã bật màn hình trước"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Trượt để dùng màn hình bên trong"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"gập"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"mở"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-vi/tiles_states_strings.xml b/packages/SystemUI/res/values-vi/tiles_states_strings.xml index 466eb3d6017c..d8e68875f07e 100644 --- a/packages/SystemUI/res/values-vi/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-vi/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Đang tắt"</item> <item msgid="5908720590832378783">"Đang bật"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 0f28d9299d68..530017cd087e 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"取消选中微件"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"减小高度"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"增加高度"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"显示下一个"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"显示上一个"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"锁屏微件"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"若要使用微件打开应用,您需要验证是您本人在操作。另外请注意,任何人都可以查看此类微件,即使您的平板电脑已锁定。有些微件可能不适合显示在锁定的屏幕中,因此添加到这里可能不安全。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"知道了"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话功能"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"反馈"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"关闭"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"不再显示"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"无法修改来电通知。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"您无法在此处配置这组通知"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展开可折叠设备"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻转可折叠设备"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"前屏已开启"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"滑动即可使用内屏"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"折叠状态"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"展开状态"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s/%2$s"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml index 65415f615ceb..6f3606578a48 100644 --- a/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"关闭"</item> <item msgid="5908720590832378783">"开启"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 6a29d86bb49f..496cbdb7b5cf 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"取消揀小工具"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"調低高度"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"調高高度"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"顯示下一個"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"顯示上一個"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"上鎖畫面小工具"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"如要使用小工具開啟應用程式,系統會要求你驗證身分。請注意,所有人都能查看小工具,即使平板電腦已鎖定亦然。部分小工具可能不適用於上鎖畫面,新增至這裡可能會有安全疑慮。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"知道了"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"意見反映"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"關閉"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"不要再顯示"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"無法修改通話通知。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在此設定這組通知"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開折疊式裝置"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"正面螢幕已開啟"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"滑動即可使用內部螢幕"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已打開"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml index 0882be746b06..25548e2d3c35 100644 --- a/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"關閉"</item> <item msgid="5908720590832378783">"開啟"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index a931304cdfbe..c63473fa0197 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -534,6 +534,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"取消選取小工具"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"調低"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"調高"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"顯示下一個"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"顯示上一個"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"螢幕鎖定小工具"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"如要使用小工具開啟應用程式,需先驗證身分。請留意,即使平板電腦已鎖定,所有人都還是能查看小工具。某些小工具可能不適用於螢幕鎖定畫面,新增到此可能會有安全疑慮。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"我知道了"</string> @@ -806,7 +808,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話功能"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"意見回饋"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"關閉"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"不要再顯示"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"無法修改來電通知。"</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"無法在這裡設定這個通知群組"</string> @@ -1394,8 +1401,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"正在展開的折疊式裝置"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"正在翻轉折疊式裝置"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"正面螢幕已開啟"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"滑動即可使用內螢幕"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"已摺疊"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"已展開"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml index f94b0449c598..3a192ba951b9 100644 --- a/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"關閉"</item> <item msgid="5908720590832378783">"開啟"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 08e685273bb3..2aad788b3cf4 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -536,6 +536,8 @@ <string name="accessibility_action_label_unselect_widget" msgid="1041811747619468698">"yeka ukukhetha iwijethi"</string> <string name="accessibility_action_label_shrink_widget" msgid="8259511040536438771">"Nciphisa ubude"</string> <string name="accessibility_action_label_expand_widget" msgid="9190524260912211759">"Khuphula ubude"</string> + <string name="accessibility_action_label_umo_show_next" msgid="8033581654789193281">"Bonisa okulandelayo"</string> + <string name="accessibility_action_label_umo_show_previous" msgid="5935831384525173810">"Bonisa okwangaphambili"</string> <string name="communal_widgets_disclaimer_title" msgid="1150954395585308868">"Amawijethi wesikrini esikhiyiwe"</string> <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Ukuze uvule i-app usebenzisa iwijethi, uzodinga ukuqinisekisa ukuthi nguwe. Futhi, khumbula ukuthi noma ubani angakwazi ukuzibuka, nanoma ithebhulethi yakho ikhiyiwe. Amanye amawijethi kungenzeka abengahloselwe ukukhiya isikrini sakho futhi kungenzeka awaphephile ukuthi angafakwa lapha."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Ngiyezwa"</string> @@ -808,7 +810,12 @@ <string name="no_shortcut" msgid="8257177117568230126">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli izici zengxoxo"</string> <string name="notification_guts_bundle_feedback" msgid="7581587973879656500">"Impendulo"</string> <string name="notification_inline_dismiss" msgid="88423586921134258">"Chitha"</string> - <string name="notification_inline_disable_promotion" msgid="6880961831026048166">"Ungabonisi futhi"</string> + <!-- no translation found for notification_inline_disable_promotion (3551682588314376921) --> + <skip /> + <!-- no translation found for live_notifications_title (1586553354601345379) --> + <skip /> + <!-- no translation found for live_notifications_desc (7470787001768372152) --> + <skip /> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Lezi zaziso azikwazi ukushintshwa."</string> <string name="notification_unblockable_call_desc" msgid="5907328164696532169">"Izaziso zekholi azikwazi ukushintshwa."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Leli qembu lezaziso alikwazi ukulungiselelwa lapha"</string> @@ -1396,8 +1403,7 @@ <string name="rear_display_accessibility_folded_animation" msgid="1538121649587978179">"Idivayisi egoqekayo iyembulwa"</string> <string name="rear_display_accessibility_unfolded_animation" msgid="1946153682258289040">"Idivayisi egoqekayo iphendulwa nxazonke"</string> <string name="rear_display_unfolded_front_screen_on" msgid="5946436677205643170">"Isikrini sangaphambili sivuliwe"</string> - <!-- no translation found for rear_display_unfolded_front_screen_on_slide_to_cancel (1455192420423012859) --> - <skip /> + <string name="rear_display_unfolded_front_screen_on_slide_to_cancel" msgid="1455192420423012859">"Slayida ukuze usebenzise isikrini esingaphakathi"</string> <string name="quick_settings_rotation_posture_folded" msgid="2430280856312528289">"kugoqiwe"</string> <string name="quick_settings_rotation_posture_unfolded" msgid="6372316273574167114">"kuvuliwe"</string> <string name="rotation_tile_with_posture_secondary_label_template" msgid="7648496484163318886">"%1$s / %2$s"</string> diff --git a/packages/SystemUI/res/values-zu/tiles_states_strings.xml b/packages/SystemUI/res/values-zu/tiles_states_strings.xml index be5c6d89b03c..f9f27bdbe251 100644 --- a/packages/SystemUI/res/values-zu/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-zu/tiles_states_strings.xml @@ -196,4 +196,7 @@ <item msgid="6419996398343291862">"Valiwe"</item> <item msgid="5908720590832378783">"Vuliwe"</item> </string-array> + <!-- no translation found for tile_states_desktopeffects:0 (6253480000354287321) --> + <!-- no translation found for tile_states_desktopeffects:1 (6641673879029894995) --> + <!-- no translation found for tile_states_desktopeffects:2 (5806682401126108403) --> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 8665fd6dcaf5..f4c6904028ca 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -198,6 +198,7 @@ <!-- media --> <color name="media_seamless_border">?android:attr/colorAccent</color> <color name="media_paging_indicator">@color/material_dynamic_neutral_variant80</color> + <color name="media_on_background">#FFFFFF</color> <!-- media output dialog--> <color name="media_dialog_background" android:lstar="98">@color/material_dynamic_neutral90</color> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 6a4a0b7893d9..8d10e393b5ca 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -175,6 +175,9 @@ <!-- Minimum display time for a heads up notification if throttling is enabled, in milliseconds. --> <integer name="heads_up_notification_minimum_time_with_throttling">500</integer> + <!-- Minimum display time for a heads up notification that was shown from a user action (like tapping on a different part of the UI), in milliseconds. --> + <integer name="heads_up_notification_minimum_time_for_user_initiated">3000</integer> + <!-- Display time for a sticky heads up notification, in milliseconds. --> <integer name="sticky_heads_up_notification_time">60000</integer> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 8cd4c1bb3533..17a89b3a0394 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -204,15 +204,31 @@ match the core/status_bar_system_icon_size and change to sp unit --> <dimen name="status_bar_mobile_signal_size">15sp</dimen> <dimen name="status_bar_mobile_signal_size_updated">12sp</dimen> + <!-- Size of the view displaying the mobile signal icon in the status bar. This value should - match the viewport height of mobile signal drawables such as ic_lte_mobiledata --> + match the viewport height of mobile signal drawables such as ic_lte_mobiledata + Note: can be removed once new_status_bar_icons is rolled out --> <dimen name="status_bar_mobile_type_size">16sp</dimen> <!-- Size of the view that contains the network type. Should be equal to - status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding --> + status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding + Note: can be removed once new_status_bar_icons is rolled out --> <dimen name="status_bar_mobile_container_height">18sp</dimen> <!-- Corner radius for the background of the network type indicator. Should be equal to - status_bar_mobile_container_height / 2 --> + status_bar_mobile_container_height / 2 + Note: can be removed once new_status_bar_icons is rolled out --> <dimen name="status_bar_mobile_container_corner_radius">9sp</dimen> + + <!-- Size of the view displaying the mobile signal icon in the status bar. This value should + match the viewport height of mobile signal drawables such as ic_lte_mobiledata --> + <dimen name="status_bar_mobile_type_size_updated">12sp</dimen> + <!-- Size of the view that contains the network type. Should be equal to + status_bar_mobile_type_size + 2, to account for 1sp top and bottom padding --> + <dimen name="status_bar_mobile_container_height_updated">14sp</dimen> + <dimen name="status_bar_mobile_container_margin_end">2sp</dimen> + <!-- Corner radius for the background of the network type indicator. Should be equal to + status_bar_mobile_container_height / 2 --> + <dimen name="status_bar_mobile_container_corner_radius_updated">7sp</dimen> + <!-- Size of the view displaying the mobile roam icon in the status bar. This value should match the viewport size of drawable stat_sys_roaming --> <dimen name="status_bar_mobile_roam_size">8sp</dimen> @@ -1806,7 +1822,8 @@ <!-- The activity chip side padding, used with the default phone icon. --> <dimen name="ongoing_activity_chip_side_padding">12dp</dimen> <!-- The activity chip side padding, used with an icon that has embedded padding (e.g. if the icon comes from the notification's smallIcon field). If the icon has padding, the chip itself can have less padding. --> - <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon">6dp</dimen> + <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon">2dp</dimen> + <dimen name="ongoing_activity_chip_side_padding_for_embedded_padding_icon_legacy">6dp</dimen> <!-- The icon size, used with the default phone icon. --> <dimen name="ongoing_activity_chip_icon_size">16dp</dimen> <!-- The icon size, used with an icon that has embedded padding. (If the icon has embedded padding, we need to make the whole icon larger so the icon itself doesn't look small.) --> @@ -2166,9 +2183,7 @@ orientation when the vertical space is limited --> <dimen name="volume_dialog_slider_vertical_margin">124dp</dimen> - - <fraction name="volume_dialog_half_opened_bias">0.2</fraction> - + <dimen name="volume_dialog_half_opened_offset">-128dp</dimen> <dimen name="volume_dialog_slider_max_deviation">56dp</dimen> <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index e077b41a6f59..359bd2bcb37c 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -574,11 +574,12 @@ <!-- Content description of the bluetooth device settings gear icon. [CHAR LIMIT=NONE] --> <string name="accessibility_bluetooth_device_settings_gear">Click to configure device detail</string> + <!-- Content description of the bluetooth device settings gear icon. [CHAR LIMIT=NONE] [BACKUP_MESSAGE_ID=3314916468105272540] --> + <string name="accessibility_bluetooth_device_settings_gear_with_name"><xliff:g id="device_name">%s</xliff:g>. Configure device detail</string> <!-- Content description of the bluetooth device settings see all. [CHAR LIMIT=NONE] --> - <string name="accessibility_bluetooth_device_settings_see_all">Click to see all devices</string> + <string name="accessibility_bluetooth_device_settings_see_all">See all devices</string> <!-- Content description of the bluetooth device settings pair new device. [CHAR LIMIT=NONE] --> - <string name="accessibility_bluetooth_device_settings_pair_new_device">Click to pair new device</string> - + <string name="accessibility_bluetooth_device_settings_pair_new_device">Pair new device</string> <!-- Content description of the battery when battery state is unknown for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_battery_unknown">Battery percentage unknown.</string> @@ -2341,7 +2342,9 @@ <!-- User visible title for the keyboard shortcut that enters split screen with current app on the left [CHAR LIMIT=70] --> <string name="system_multitasking_lhs">Use split screen with app on the left</string> <!-- User visible title for the keyboard shortcut that switches from split screen to full screen [CHAR LIMIT=70] --> - <string name="system_multitasking_full_screen">Switch to full screen</string> + <string name="system_multitasking_full_screen">Use full screen</string> + <!-- User visible title for the keyboard shortcut that switches to desktop view [CHAR LIMIT=70] --> + <string name="system_multitasking_desktop_view">Use desktop view</string> <!-- User visible title for the keyboard shortcut that switches to app on right or below while using split screen [CHAR LIMIT=70] --> <string name="system_multitasking_splitscreen_focus_rhs">Switch to app on right or below while using split screen</string> <!-- User visible title for the keyboard shortcut that switches to app on left or above while using split screen [CHAR LIMIT=70] --> @@ -2557,6 +2560,9 @@ <!-- SysUI Tuner: Other section --> <string name="other">Other</string> + <!-- Accessibility description of action to toggle QS tile size on click. It will read as "Double-tap to toggle the tile's size" in screen readers [CHAR LIMIT=NONE] --> + <string name="accessibility_qs_edit_toggle_tile_size_action">toggle the tile\'s size</string> + <!-- Accessibility description of action to remove QS tile on click. It will read as "Double-tap to remove tile" in screen readers [CHAR LIMIT=NONE] --> <string name="accessibility_qs_edit_remove_tile_action">remove tile</string> @@ -3164,8 +3170,8 @@ <string name="controls_media_settings_button">Settings</string> <!-- Description for media control's playing media item, including information for the media's title, the artist, and source app [CHAR LIMIT=NONE]--> <string name="controls_media_playing_item_description"><xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> by <xliff:g id="artist_name" example="Various artists">%2$s</xliff:g> is playing from <xliff:g id="app_label" example="Spotify">%3$s</xliff:g></string> - <!-- Content description for media cotnrols progress bar [CHAR_LIMIT=NONE] --> - <string name="controls_media_seekbar_description"><xliff:g id="elapsed_time" example="1:30">%1$s</xliff:g> of <xliff:g id="total_time" example="3:00">%2$s</xliff:g></string> + <!-- Content description for media controls progress bar [CHAR_LIMIT=NONE] --> + <string name="controls_media_seekbar_description"><xliff:g id="elapsed_time" example="1 hour 2 minutes 30 seconds">%1$s</xliff:g> of <xliff:g id="total_time" example="4 hours 5 seconds">%2$s</xliff:g></string> <!-- Placeholder title to inform user that an app has posted media controls [CHAR_LIMIT=NONE] --> <string name="controls_media_empty_title"><xliff:g id="app_name" example="Foo Music App">%1$s</xliff:g> is running</string> @@ -4007,6 +4013,8 @@ <string name="touchpad_tutorial_switch_apps_gesture_button">Switch apps</string> <!-- Label for button finishing touchpad tutorial [CHAR LIMIT=NONE] --> <string name="touchpad_tutorial_done_button">Done</string> + <!-- Label for button proceeding touchpad tutorial [CHAR LIMIT=NONE] --> + <string name="touchpad_tutorial_next_button">Next</string> <!-- Screen title after gesture was not done correctly [CHAR LIMIT=NONE] --> <string name="gesture_error_title">Try again!</string> <!-- BACK GESTURE --> @@ -4092,8 +4100,10 @@ <!-- Title of the one line view of a redacted notification --> <string name="redacted_notification_single_line_title">Redacted</string> - <!-- Main text of the one line view of a redacted notification --> - <string name="redacted_notification_single_line_text">Unlock to view</string> + <!-- Main text of the one line view of a public notification --> + <string name="public_notification_single_line_text">Unlock to view</string> + <!-- Main text of the one line view of a redacted OTP notification --> + <string name="redacted_otp_notification_single_line_text">Unlock to view code</string> <!-- Content description for contextual education dialog [CHAR LIMIT=NONE] --> <string name="contextual_education_dialog_title">Contextual education</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 8f808d389203..8a6b3af172d7 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -186,7 +186,7 @@ </style> <style name="TextAppearance.QS.Status.Build"> - <item name="android:textColor">?attr/onSurfaceVariant</item> + <item name="android:textColor">?attr/onShadeInactiveVariant</item> </style> <style name="TextAppearance.DeviceManagementDialog.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/> @@ -828,23 +828,23 @@ <item name="android:elevation">10dp</item> </style> - <!-- Media controls always have light background --> + <!-- Media controls always have dark background --> <style name="MediaPlayer" parent="@*android:style/Theme.DeviceDefault.Light"> - <item name="android:textColor">?android:attr/textColorPrimary</item> - <item name="android:backgroundTint">@color/material_dynamic_secondary95</item> + <item name="android:textColor">@color/media_on_background</item> + <item name="android:backgroundTint">@android:color/system_on_surface_light</item> </style> <style name="MediaPlayer.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal"> <item name="android:thumb">@drawable/media_seekbar_thumb</item> - <item name="android:thumbTint">?android:attr/textColorPrimary</item> + <item name="android:thumbTint">@color/media_on_background</item> <item name="android:progressDrawable">@drawable/media_squiggly_progress</item> - <item name="android:progressTint">?android:attr/textColorPrimary</item> - <item name="android:progressBackgroundTint">?android:attr/textColorTertiary</item> + <item name="android:progressTint">@color/media_on_background</item> + <item name="android:progressBackgroundTint">@android:color/system_primary_dark</item> <item name="android:splitTrack">false</item> </style> <style name="MediaPlayer.Subtitle" parent="MediaPlayer"> - <item name="android:textColor">?android:attr/textColorSecondary</item> + <item name="android:textColor">@color/media_on_background</item> </style> <style name="MediaPlayer.ScrubbingTime"> @@ -853,21 +853,10 @@ <item name="android:gravity">center</item> </style> - <style name="MediaPlayer.Action" parent="@android:style/Widget.Material.Button.Borderless.Small"> - <item name="android:background">@drawable/qs_media_light_source</item> - <item name="android:tint">?android:attr/textColorPrimary</item> - <item name="android:stateListAnimator">@anim/media_button_state_list_animator</item> - <item name="android:paddingTop">8dp</item> - <item name="android:paddingStart">12dp</item> - <item name="android:paddingEnd">12dp</item> - <item name="android:paddingBottom">16dp</item> - <item name="android:scaleType">centerInside</item> - </style> - <style name="MediaPlayer.SessionAction" parent="@android:style/Widget.Material.Button.Borderless.Small"> <item name="android:background">@drawable/qs_media_light_source</item> - <item name="android:tint">?android:attr/textColorPrimary</item> + <item name="android:tint">@color/media_on_background</item> <item name="android:paddingTop">12dp</item> <item name="android:paddingStart">12dp</item> <item name="android:paddingEnd">12dp</item> @@ -886,8 +875,8 @@ <style name="MediaPlayer.OutlineButton"> <item name="android:background">@drawable/qs_media_outline_button</item> - <item name="android:textColor">?android:attr/textColorPrimary</item> - <item name="android:backgroundTint">@color/media_player_outline_button_bg</item> + <item name="android:textColor">@color/media_on_background</item> + <item name="android:backgroundTint">@android:color/system_primary_dark</item> <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> <item name="android:layout_gravity">center</item> <item name="android:singleLine">true</item> @@ -895,8 +884,8 @@ <style name="MediaPlayer.SolidButton"> <item name="android:backgroundTint">@color/media_player_solid_button_bg</item> - <item name="android:tint">?android:attr/colorPrimary</item> - <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:tint">@android:color/system_on_primary_dark</item> + <item name="android:textColor">@android:color/system_on_primary_dark</item> </style> <style name="MediaPlayer.Recommendation"/> diff --git a/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml deleted file mode 100644 index dcc5d4f6635f..000000000000 --- a/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/volume_dialog_constraint_set"> - - <Constraint - android:id="@id/volume_dialog_main_slider_container" - android:layout_width="@dimen/volume_dialog_slider_width" - android:layout_height="0dp" - android:layout_marginTop="@dimen/volume_dialog_slider_vertical_margin" - android:layout_marginEnd="@dimen/volume_dialog_window_margin" - android:layout_marginBottom="@dimen/volume_dialog_slider_vertical_margin" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHeight_max="@dimen/volume_dialog_slider_height" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="0.5" /> -</ConstraintSet>
\ No newline at end of file diff --git a/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml deleted file mode 100644 index 3a5e41d5781a..000000000000 --- a/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/volume_dialog_half_folded_constraint_set"> - - <Constraint - android:id="@id/volume_dialog_main_slider_container" - android:layout_width="@dimen/volume_dialog_slider_width" - android:layout_height="0dp" - android:layout_marginTop="@dimen/volume_dialog_slider_vertical_margin" - android:layout_marginEnd="@dimen/volume_dialog_window_margin" - android:layout_marginBottom="@dimen/volume_dialog_slider_vertical_margin" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHeight_max="@dimen/volume_dialog_slider_height" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="@fraction/volume_dialog_half_opened_bias" /> -</ConstraintSet>
\ No newline at end of file diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 0f1da509468a..ae3a76e2d2ca 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -71,6 +71,7 @@ android_library { "//frameworks/libs/systemui:com_android_systemui_shared_flags_lib", "//frameworks/libs/systemui:msdl", "//frameworks/libs/systemui:view_capture", + "am_flags_lib", ], resource_dirs: [ "res", diff --git a/packages/SystemUI/shared/res/values/bools.xml b/packages/SystemUI/shared/res/values/bools.xml index f22dac4b9fb4..98e5cea0e78f 100644 --- a/packages/SystemUI/shared/res/values/bools.xml +++ b/packages/SystemUI/shared/res/values/bools.xml @@ -22,4 +22,7 @@ <resources> <!-- Whether to add padding at the bottom of the complication clock --> <bool name="dream_overlay_complication_clock_bottom_padding">false</bool> -</resources>
\ No newline at end of file + + <!-- Whether to mark tasks that are present in the UI as perceptible tasks. --> + <bool name="config_usePerceptibleTasks">false</bool> +</resources> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index ed9ba7aa455b..26d78bbee8e5 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -46,6 +46,8 @@ import android.view.Display; import android.window.TaskSnapshot; import com.android.internal.app.IVoiceInteractionManagerService; +import com.android.server.am.Flags; +import com.android.systemui.shared.R; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -227,6 +229,17 @@ public class ActivityManagerWrapper { } /** + * Sets whether or not the specified task is perceptible. + */ + public boolean setTaskIsPerceptible(int taskId, boolean isPerceptible) { + try { + return getService().setTaskIsPerceptible(taskId, isPerceptible); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Removes a task by id. */ public void removeTask(final int taskId) { @@ -311,6 +324,14 @@ public class ActivityManagerWrapper { } /** + * Returns true if tasks with a presence in the UI should be marked as perceptible tasks. + */ + public static boolean usePerceptibleTasks(Context context) { + return Flags.perceptibleTasks() + && context.getResources().getBoolean(R.bool.config_usePerceptibleTasks); + } + + /** * Returns true if the running task represents the home task */ public static boolean isHomeTask(RunningTaskInfo info) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java index f528ec8af134..860a496ef18b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java @@ -20,22 +20,16 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.hardware.biometrics.BiometricSourceType; import android.os.SystemClock; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; import android.util.Log; import android.util.Pair; import android.view.View; import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import com.android.systemui.util.ViewController; -import java.lang.ref.WeakReference; - import javax.inject.Inject; /** @@ -54,39 +48,8 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> private Pair<BiometricSourceType, Long> mMessageBiometricSource = null; private static final Long SKIP_SHOWING_FACE_MESSAGE_AFTER_FP_MESSAGE_MS = 3500L; - /** - * Delay before speaking an accessibility announcement. Used to prevent - * lift-to-type from interrupting itself. - */ - private static final long ANNOUNCEMENT_DELAY = 250; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final ConfigurationController mConfigurationController; - private final AnnounceRunnable mAnnounceRunnable; - private final TextWatcher mTextWatcher = new TextWatcher() { - @Override - public void afterTextChanged(Editable editable) { - CharSequence msg = editable; - if (!TextUtils.isEmpty(msg)) { - mView.removeCallbacks(mAnnounceRunnable); - mAnnounceRunnable.setTextToAnnounce(msg); - mView.postDelayed(() -> { - if (msg == mView.getText()) { - mAnnounceRunnable.run(); - } - }, ANNOUNCEMENT_DELAY); - } - } - - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { - /* no-op */ - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - /* no-op */ - } - }; private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() { public void onFinishedGoingToSleep(int why) { @@ -122,7 +85,6 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> mKeyguardUpdateMonitor = keyguardUpdateMonitor; mConfigurationController = configurationController; - mAnnounceRunnable = new AnnounceRunnable(mView); } @Override @@ -131,14 +93,12 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> mKeyguardUpdateMonitor.registerCallback(mInfoCallback); mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive()); mView.onThemeChanged(); - mView.addTextChangedListener(mTextWatcher); } @Override protected void onViewDetached() { mConfigurationController.removeCallback(mConfigurationListener); mKeyguardUpdateMonitor.removeCallback(mInfoCallback); - mView.removeTextChangedListener(mTextWatcher); } /** @@ -232,30 +192,4 @@ public class KeyguardMessageAreaController<T extends KeyguardMessageArea> view, mKeyguardUpdateMonitor, mConfigurationController); } } - - /** - * Runnable used to delay accessibility announcements. - */ - @VisibleForTesting - public static class AnnounceRunnable implements Runnable { - private final WeakReference<View> mHost; - private CharSequence mTextToAnnounce; - - AnnounceRunnable(View host) { - mHost = new WeakReference<>(host); - } - - /** Sets the text to announce. */ - public void setTextToAnnounce(CharSequence textToAnnounce) { - mTextToAnnounce = textToAnnounce; - } - - @Override - public void run() { - final View host = mHost.get(); - if (host != null && host.isVisibleToUser()) { - host.announceForAccessibility(mTextToAnnounce); - } - } - } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java index 5d63c2a92ba8..4a4cb7a232c5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java @@ -43,6 +43,8 @@ import com.android.internal.widget.LockPatternView; import com.android.settingslib.animation.AppearAnimationCreator; import com.android.settingslib.animation.AppearAnimationUtils; import com.android.settingslib.animation.DisappearAnimationUtils; +import com.android.systemui.Flags; +import com.android.systemui.bouncer.shared.constants.PatternBouncerConstants.ColorId; import com.android.systemui.res.R; import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt; @@ -227,6 +229,18 @@ public class KeyguardPatternView extends KeyguardInputView super.onFinishInflate(); mLockPatternView = findViewById(R.id.lockPatternView); + if (Flags.bouncerUiRevamp2()) { + mLockPatternView.setDotColors(mContext.getColor(ColorId.dotColor), mContext.getColor( + ColorId.activatedDotColor)); + mLockPatternView.setColors(mContext.getColor(ColorId.pathColor), 0, 0); + mLockPatternView.setDotSizes( + getResources().getDimensionPixelSize(R.dimen.keyguard_pattern_dot_size), + getResources().getDimensionPixelSize( + R.dimen.keyguard_pattern_activated_dot_size)); + mLockPatternView.setPathWidth( + getResources().getDimensionPixelSize(R.dimen.keyguard_pattern_stroke_width)); + mLockPatternView.setKeepDotActivated(true); + } mEcaView = findViewById(R.id.keyguard_selector_fade_container); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index 245283da75ab..04d4c2a3cdf9 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -184,7 +184,9 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView } mDeleteButton = findViewById(R.id.delete_button); if (Flags.bouncerUiRevamp2()) { - mDeleteButton.setImageResource(R.drawable.pin_bouncer_delete); + mDeleteButton.setDrawableForTransparentMode(R.drawable.pin_bouncer_delete_filled); + mDeleteButton.setDefaultDrawable(R.drawable.pin_bouncer_delete_outline); + mDeleteButton.setImageResource(R.drawable.pin_bouncer_delete_outline); } mDeleteButton.setVisibility(View.VISIBLE); diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java index 0ff93236a856..584ebb50520a 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java @@ -25,6 +25,7 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.view.accessibility.AccessibilityNodeInfo; +import androidx.annotation.DrawableRes; import androidx.annotation.Nullable; import com.android.systemui.Flags; @@ -42,6 +43,12 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni private int mStyleAttr; private boolean mIsTransparentMode; + @DrawableRes + private int mDrawableForTransparentMode = 0; + + @DrawableRes + private int mDefaultDrawable = 0; + public NumPadButton(Context context, AttributeSet attrs) { super(context, attrs); mStyleAttr = attrs.getStyleAttribute(); @@ -123,8 +130,14 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni mIsTransparentMode = isTransparentMode; if (isTransparentMode) { + if (mDrawableForTransparentMode != 0) { + setImageResource(mDrawableForTransparentMode); + } setBackgroundColor(getResources().getColor(android.R.color.transparent)); } else { + if (mDefaultDrawable != 0) { + setImageResource(mDefaultDrawable); + } Drawable bgDrawable = getContext().getDrawable(R.drawable.num_pad_key_background); if (Flags.bouncerUiRevamp2() && bgDrawable != null) { bgDrawable.setTint(Color.actionBg); @@ -154,4 +167,19 @@ public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAni super.onInitializeAccessibilityNodeInfo(info); info.setTextEntryKey(true); } + + /** + * Drawable to use when transparent mode is enabled + */ + public void setDrawableForTransparentMode(@DrawableRes int drawableResId) { + mDrawableForTransparentMode = drawableResId; + } + + /** + * Drawable to use when transparent mode is not enabled. + */ + public void setDefaultDrawable(@DrawableRes int drawableResId) { + mDefaultDrawable = drawableResId; + setImageResource(mDefaultDrawable); + } } diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java index 42896a419658..b2cb357fabc8 100644 --- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java +++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java @@ -167,7 +167,7 @@ public class ExpandHelper implements Gefingerpoken { public void setHeight(float h) { if (DEBUG_SCALE) Log.v(TAG, "SetHeight: setting to " + h); - mView.setActualHeight((int) h); + mView.setFinalActualHeight((int) h); mCurrentHeight = h; } public float getHeight() { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java index 7c141c1b561e..5247acc94e03 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeLayout.java @@ -58,11 +58,22 @@ public class AmbientVolumeLayout extends LinearLayout implements AmbientVolumeUi private final BiMap<Integer, AmbientVolumeSlider> mSideToSliderMap = HashBiMap.create(); private int mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT; + private HearingDevicesUiEventLogger mUiEventLogger; + private int mLaunchSourceId; + private final AmbientVolumeSlider.OnChangeListener mSliderOnChangeListener = (slider, value) -> { - if (mListener != null) { - final int side = mSideToSliderMap.inverse().get(slider); - mListener.onSliderValueChange(side, value); + final Integer side = mSideToSliderMap.inverse().get(slider); + if (side != null) { + if (mUiEventLogger != null) { + HearingDevicesUiEvent uiEvent = side == SIDE_UNIFIED + ? HearingDevicesUiEvent.HEARING_DEVICES_AMBIENT_CHANGE_UNIFIED + : HearingDevicesUiEvent.HEARING_DEVICES_AMBIENT_CHANGE_SEPARATED; + mUiEventLogger.log(uiEvent, mLaunchSourceId); + } + if (mListener != null) { + mListener.onSliderValueChange(side, value); + } } }; @@ -94,6 +105,12 @@ public class AmbientVolumeLayout extends LinearLayout implements AmbientVolumeUi return; } setMuted(!mMuted); + if (mUiEventLogger != null) { + HearingDevicesUiEvent uiEvent = mMuted + ? HearingDevicesUiEvent.HEARING_DEVICES_AMBIENT_MUTE + : HearingDevicesUiEvent.HEARING_DEVICES_AMBIENT_UNMUTE; + mUiEventLogger.log(uiEvent, mLaunchSourceId); + } if (mListener != null) { mListener.onAmbientVolumeIconClick(); } @@ -103,6 +120,12 @@ public class AmbientVolumeLayout extends LinearLayout implements AmbientVolumeUi mExpandIcon = requireViewById(R.id.ambient_expand_icon); mExpandIcon.setOnClickListener(v -> { setExpanded(!mExpanded); + if (mUiEventLogger != null) { + HearingDevicesUiEvent uiEvent = mExpanded + ? HearingDevicesUiEvent.HEARING_DEVICES_AMBIENT_EXPAND_CONTROLS + : HearingDevicesUiEvent.HEARING_DEVICES_AMBIENT_COLLAPSE_CONTROLS; + mUiEventLogger.log(uiEvent, mLaunchSourceId); + } if (mListener != null) { mListener.onExpandIconClick(); } @@ -243,6 +266,11 @@ public class AmbientVolumeLayout extends LinearLayout implements AmbientVolumeUi updateVolumeLevel(); } + void setUiEventLogger(HearingDevicesUiEventLogger uiEventLogger, int launchSourceId) { + mUiEventLogger = uiEventLogger; + mLaunchSourceId = launchSourceId; + } + private void updateVolumeLevel() { int leftLevel, rightLevel; if (mExpanded) { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java index 438184d4d2d6..786d27af3994 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java @@ -30,7 +30,6 @@ import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.media.AudioManager; import android.os.Bundle; -import android.os.Handler; import android.provider.Settings; import android.util.Log; import android.view.LayoutInflater; @@ -49,6 +48,7 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.annotation.WorkerThread; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -57,7 +57,6 @@ import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; -import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.accessibility.hearingaid.HearingDevicesListAdapter.HearingDeviceItemCallback; import com.android.systemui.animation.DialogTransitionAnimator; import com.android.systemui.bluetooth.qsdialog.ActiveHearingDeviceItemFactory; @@ -67,6 +66,7 @@ import com.android.systemui.bluetooth.qsdialog.DeviceItem; import com.android.systemui.bluetooth.qsdialog.DeviceItemFactory; import com.android.systemui.bluetooth.qsdialog.DeviceItemType; import com.android.systemui.bluetooth.qsdialog.SavedHearingDeviceItemFactory; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.res.R; @@ -79,6 +79,7 @@ import dagger.assisted.AssistedInject; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.stream.Collectors; /** @@ -101,7 +102,8 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, private final DialogTransitionAnimator mDialogTransitionAnimator; private final ActivityStarter mActivityStarter; private final LocalBluetoothManager mLocalBluetoothManager; - private final Handler mMainHandler; + private final Executor mMainExecutor; + private final Executor mBgExecutor; private final AudioManager mAudioManager; private final LocalBluetoothProfileManager mProfileManager; private final HearingDevicesUiEventLogger mUiEventLogger; @@ -109,8 +111,6 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, private final int mLaunchSourceId; private SystemUIDialog mDialog; - - private List<DeviceItem> mHearingDeviceItemList; private HearingDevicesListAdapter mDeviceListAdapter; private View mPresetLayout; @@ -122,14 +122,14 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, @Override public void onPresetInfoUpdated(List<BluetoothHapPresetInfo> presetInfos, int activePresetIndex) { - mMainHandler.post( + mMainExecutor.execute( () -> refreshPresetUi(presetInfos, activePresetIndex)); } @Override public void onPresetCommandFailed(int reason) { mPresetController.refreshPresetInfo(); - mMainHandler.post(() -> { + mMainExecutor.execute(() -> { showErrorToast(R.string.hearing_devices_presets_error); }); } @@ -166,7 +166,8 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, ActivityStarter activityStarter, DialogTransitionAnimator dialogTransitionAnimator, @Nullable LocalBluetoothManager localBluetoothManager, - @Main Handler handler, + @Main Executor mainExecutor, + @Background Executor bgExecutor, AudioManager audioManager, HearingDevicesUiEventLogger uiEventLogger) { mShowPairNewDevice = showPairNewDevice; @@ -174,7 +175,8 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, mActivityStarter = activityStarter; mDialogTransitionAnimator = dialogTransitionAnimator; mLocalBluetoothManager = localBluetoothManager; - mMainHandler = handler; + mMainExecutor = mainExecutor; + mBgExecutor = bgExecutor; mAudioManager = audioManager; mProfileManager = localBluetoothManager.getProfileManager(); mUiEventLogger = uiEventLogger; @@ -227,9 +229,10 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, @Override public void onActiveDeviceChanged(@Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) { - refreshDeviceUi(); - mMainHandler.post(() -> { - CachedBluetoothDevice device = getActiveHearingDevice(); + List<DeviceItem> hearingDeviceItemList = getHearingDeviceItemList(); + refreshDeviceUi(hearingDeviceItemList); + mMainExecutor.execute(() -> { + CachedBluetoothDevice device = getActiveHearingDevice(hearingDeviceItemList); if (mPresetController != null) { mPresetController.setDevice(device); mPresetLayout.setVisibility( @@ -244,13 +247,15 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, @Override public void onProfileConnectionStateChanged(@NonNull CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) { - refreshDeviceUi(); + List<DeviceItem> hearingDeviceItemList = getHearingDeviceItemList(); + refreshDeviceUi(hearingDeviceItemList); } @Override public void onAclConnectionStateChanged(@NonNull CachedBluetoothDevice cachedDevice, int state) { - refreshDeviceUi(); + List<DeviceItem> hearingDeviceItemList = getHearingDeviceItemList(); + refreshDeviceUi(hearingDeviceItemList); } @Override @@ -280,18 +285,25 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_DIALOG_SHOW, mLaunchSourceId); - setupDeviceListView(dialog); - setupPairNewDeviceButton(dialog); - setupPresetSpinner(dialog); - if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) { - setupAmbientControls(); - } - setupRelatedToolsView(dialog); + mBgExecutor.execute(() -> { + List<DeviceItem> hearingDeviceItemList = getHearingDeviceItemList(); + CachedBluetoothDevice activeHearingDevice = getActiveHearingDevice( + hearingDeviceItemList); + mMainExecutor.execute(() -> { + setupDeviceListView(dialog, hearingDeviceItemList); + setupPairNewDeviceButton(dialog); + setupPresetSpinner(dialog, activeHearingDevice); + if (com.android.settingslib.flags.Flags.hearingDevicesAmbientVolumeControl()) { + setupAmbientControls(activeHearingDevice); + } + setupRelatedToolsView(dialog); + }); + }); } @Override public void onStart(@NonNull SystemUIDialog dialog) { - ThreadUtils.postOnBackgroundThread(() -> { + mBgExecutor.execute(() -> { if (mLocalBluetoothManager != null) { mLocalBluetoothManager.getEventManager().registerCallback(this); } @@ -306,7 +318,7 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, @Override public void onStop(@NonNull SystemUIDialog dialog) { - ThreadUtils.postOnBackgroundThread(() -> { + mBgExecutor.execute(() -> { if (mLocalBluetoothManager != null) { mLocalBluetoothManager.getEventManager().unregisterCallback(this); } @@ -319,17 +331,18 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, }); } - private void setupDeviceListView(SystemUIDialog dialog) { + private void setupDeviceListView(SystemUIDialog dialog, + List<DeviceItem> hearingDeviceItemList) { final RecyclerView deviceList = dialog.requireViewById(R.id.device_list); deviceList.setLayoutManager(new LinearLayoutManager(dialog.getContext())); - mHearingDeviceItemList = getHearingDeviceItemList(); - mDeviceListAdapter = new HearingDevicesListAdapter(mHearingDeviceItemList, this); + mDeviceListAdapter = new HearingDevicesListAdapter(hearingDeviceItemList, this); deviceList.setAdapter(mDeviceListAdapter); } - private void setupPresetSpinner(SystemUIDialog dialog) { + private void setupPresetSpinner(SystemUIDialog dialog, + CachedBluetoothDevice activeHearingDevice) { mPresetController = new HearingDevicesPresetsController(mProfileManager, mPresetCallback); - mPresetController.setDevice(getActiveHearingDevice()); + mPresetController.setDevice(activeHearingDevice); mPresetSpinner = dialog.requireViewById(R.id.preset_spinner); mPresetInfoAdapter = new HearingDevicesSpinnerAdapter(dialog.getContext()); @@ -367,12 +380,13 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, mPresetLayout.setVisibility(mPresetController.isPresetControlAvailable() ? VISIBLE : GONE); } - private void setupAmbientControls() { + private void setupAmbientControls(CachedBluetoothDevice activeHearingDevice) { final AmbientVolumeLayout ambientLayout = mDialog.requireViewById(R.id.ambient_layout); + ambientLayout.setUiEventLogger(mUiEventLogger, mLaunchSourceId); mAmbientController = new AmbientVolumeUiController( mDialog.getContext(), mLocalBluetoothManager, ambientLayout); mAmbientController.setShowUiWhenLocalDataExist(false); - mAmbientController.loadDevice(getActiveHearingDevice()); + mAmbientController.loadDevice(activeHearingDevice); } private void setupPairNewDeviceButton(SystemUIDialog dialog) { @@ -429,10 +443,11 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, } } - private void refreshDeviceUi() { - mHearingDeviceItemList = getHearingDeviceItemList(); - mMainHandler.post(() -> { - mDeviceListAdapter.refreshDeviceItemList(mHearingDeviceItemList); + private void refreshDeviceUi(List<DeviceItem> hearingDeviceItemList) { + mMainExecutor.execute(() -> { + if (mDeviceListAdapter != null) { + mDeviceListAdapter.refreshDeviceItemList(hearingDeviceItemList); + } }); } @@ -463,21 +478,27 @@ public class HearingDevicesDialogDelegate implements SystemUIDialog.Delegate, } @Nullable - private CachedBluetoothDevice getActiveHearingDevice() { - return mHearingDeviceItemList.stream() + private static CachedBluetoothDevice getActiveHearingDevice( + List<DeviceItem> hearingDeviceItemList) { + return hearingDeviceItemList.stream() .filter(item -> item.getType() == DeviceItemType.ACTIVE_MEDIA_BLUETOOTH_DEVICE) .map(DeviceItem::getCachedBluetoothDevice) .findFirst() .orElse(null); } + @WorkerThread private DeviceItem createHearingDeviceItem(CachedBluetoothDevice cachedDevice) { final Context context = mDialog.getContext(); if (cachedDevice == null) { return null; } + int mode = mAudioManager.getMode(); + boolean isOngoingCall = mode == AudioManager.MODE_RINGTONE + || mode == AudioManager.MODE_IN_CALL + || mode == AudioManager.MODE_IN_COMMUNICATION; for (DeviceItemFactory itemFactory : mHearingDeviceItemFactoryList) { - if (itemFactory.isFilterMatched(context, cachedDevice, mAudioManager)) { + if (itemFactory.isFilterMatched(context, cachedDevice, isOngoingCall)) { return itemFactory.create(context, cachedDevice); } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt index 9e77b02be495..fe1d5040c6f5 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt @@ -29,7 +29,17 @@ enum class HearingDevicesUiEvent(private val id: Int) : UiEventLogger.UiEventEnu @UiEvent(doc = "Click on the device gear to enter device detail page") HEARING_DEVICES_GEAR_CLICK(1853), @UiEvent(doc = "Select a preset from preset spinner") HEARING_DEVICES_PRESET_SELECT(1854), - @UiEvent(doc = "Click on related tool") HEARING_DEVICES_RELATED_TOOL_CLICK(1856); + @UiEvent(doc = "Click on related tool") HEARING_DEVICES_RELATED_TOOL_CLICK(1856), + @UiEvent(doc = "Change the ambient volume with unified control") + HEARING_DEVICES_AMBIENT_CHANGE_UNIFIED(2149), + @UiEvent(doc = "Change the ambient volume with separated control") + HEARING_DEVICES_AMBIENT_CHANGE_SEPARATED(2150), + @UiEvent(doc = "Mute the ambient volume") HEARING_DEVICES_AMBIENT_MUTE(2151), + @UiEvent(doc = "Unmute the ambient volume") HEARING_DEVICES_AMBIENT_UNMUTE(2152), + @UiEvent(doc = "Expand the ambient volume controls") + HEARING_DEVICES_AMBIENT_EXPAND_CONTROLS(2153), + @UiEvent(doc = "Collapse the ambient volume controls") + HEARING_DEVICES_AMBIENT_COLLAPSE_CONTROLS(2154); override fun getId(): Int = this.id } diff --git a/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS b/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS index 429b4b0fccab..329aa07fdd9e 100644 --- a/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/ailabs/OWNERS @@ -3,6 +3,5 @@ dupin@google.com linyuh@google.com pauldpong@google.com -praveenj@google.com vicliang@google.com yuklimko@google.com diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index b6537118324e..4c8a8f1c13d7 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -33,6 +33,7 @@ import android.graphics.PixelFormat; import android.hardware.biometrics.BiometricAuthenticator.Modality; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager.Authenticators; +import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.PromptInfo; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; @@ -100,7 +101,7 @@ import javax.inject.Provider; */ @Deprecated public class AuthContainerView extends LinearLayout - implements AuthDialog, WakefulnessLifecycle.Observer, CredentialView.Host { + implements WakefulnessLifecycle.Observer, CredentialView.Host { private static final String TAG = "AuthContainerView"; @@ -158,12 +159,11 @@ public class AuthContainerView extends LinearLayout private final Set<Integer> mFailedModalities = new HashSet<Integer>(); private final OnBackInvokedCallback mBackCallback = this::onBackInvoked; - private final @Background DelayableExecutor mBackgroundExecutor; private final MSDLPlayer mMSDLPlayer; // Non-null only if the dialog is in the act of dismissing and has not sent the reason yet. - @Nullable @AuthDialogCallback.DismissedReason private Integer mPendingCallbackReason; + @Nullable @BiometricPrompt.DismissedReason private Integer mPendingCallbackReason; // HAT received from LockSettingsService when credential is verified. @Nullable private byte[] mCredentialAttestation; @@ -188,18 +188,18 @@ public class AuthContainerView extends LinearLayout final class BiometricCallback implements Spaghetti.Callback { @Override public void onAuthenticated() { - animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED); + animateAway(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED); } @Override public void onUserCanceled() { sendEarlyUserCanceled(); - animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); + animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); } @Override public void onButtonNegative() { - animateAway(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE); + animateAway(BiometricPrompt.DISMISSED_REASON_NEGATIVE); } @Override @@ -210,12 +210,12 @@ public class AuthContainerView extends LinearLayout @Override public void onContentViewMoreOptionsButtonPressed() { - animateAway(AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS); + animateAway(BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS); } @Override public void onError() { - animateAway(AuthDialogCallback.DISMISSED_ERROR); + animateAway(BiometricPrompt.DISMISSED_REASON_ERROR); } @Override @@ -234,20 +234,20 @@ public class AuthContainerView extends LinearLayout @Override public void onAuthenticatedAndConfirmed() { - animateAway(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE); + animateAway(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED); } } @Override public void onCredentialMatched(@NonNull byte[] attestation) { mCredentialAttestation = attestation; - animateAway(AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED); + animateAway(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED); } @Override public void onCredentialAborted() { sendEarlyUserCanceled(); - animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); + animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); } @Override @@ -277,7 +277,7 @@ public class AuthContainerView extends LinearLayout com.android.settingslib.R.string.failed_attempts_now_wiping_dialog_dismiss, null /* OnClickListener */) .setOnDismissListener( - dialog -> animateAway(AuthDialogCallback.DISMISSED_ERROR)) + dialog -> animateAway(BiometricPrompt.DISMISSED_REASON_ERROR)) .create(); alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); alertDialog.show(); @@ -349,7 +349,6 @@ public class AuthContainerView extends LinearLayout mPanelView = mLayout.findViewById(R.id.panel); mPanelController = new AuthPanelController(mContext, mPanelView); - mBackgroundExecutor = bgExecutor; mInteractionJankMonitor = jankMonitor; mCredentialViewModelProvider = credentialViewModelProvider; @@ -394,7 +393,7 @@ public class AuthContainerView extends LinearLayout @VisibleForTesting public void onBackInvoked() { sendEarlyUserCanceled(); - animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); + animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); } void sendEarlyUserCanceled() { @@ -402,7 +401,6 @@ public class AuthContainerView extends LinearLayout BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL, getRequestId()); } - @Override public boolean isAllowDeviceCredentials() { return Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo); } @@ -450,7 +448,6 @@ public class AuthContainerView extends LinearLayout mPanelController.setContainerDimensions(getMeasuredWidth(), getMeasuredHeight()); } - @Override public void onOrientationChanged() { } @@ -538,10 +535,9 @@ public class AuthContainerView extends LinearLayout @Override public void onStartedGoingToSleep() { - animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); + animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); } - @Override public void show(WindowManager wm) { wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle())); } @@ -559,7 +555,6 @@ public class AuthContainerView extends LinearLayout } } - @Override public void dismissWithoutCallback(boolean animate) { if (animate) { animateAway(false /* sendReason */, 0 /* reason */); @@ -569,12 +564,10 @@ public class AuthContainerView extends LinearLayout } } - @Override public void dismissFromSystemServer() { animateAway(false /* sendReason */, 0 /* reason */); } - @Override public void onAuthenticationSucceeded(@Modality int modality) { if (mBiometricView != null) { mBiometricView.onAuthenticationSucceeded(modality); @@ -583,7 +576,6 @@ public class AuthContainerView extends LinearLayout } } - @Override public void onAuthenticationFailed(@Modality int modality, String failureReason) { if (mBiometricView != null) { mFailedModalities.add(modality); @@ -593,7 +585,6 @@ public class AuthContainerView extends LinearLayout } } - @Override public void onHelp(@Modality int modality, String help) { if (mBiometricView != null) { mBiometricView.onHelp(modality, help); @@ -602,7 +593,6 @@ public class AuthContainerView extends LinearLayout } } - @Override public void onError(@Modality int modality, String error) { if (mBiometricView != null) { mBiometricView.onError(modality, error); @@ -611,7 +601,6 @@ public class AuthContainerView extends LinearLayout } } - @Override public void onPointerDown() { if (mBiometricView != null) { if (mFailedModalities.contains(TYPE_FACE)) { @@ -624,22 +613,18 @@ public class AuthContainerView extends LinearLayout } } - @Override public String getOpPackageName() { return mConfig.mOpPackageName; } - @Override public String getClassNameIfItIsConfirmDeviceCredentialActivity() { return mConfig.mPromptInfo.getClassNameIfItIsConfirmDeviceCredentialActivity(); } - @Override public long getRequestId() { return mConfig.mRequestId; } - @Override public void animateToCredentialUI(boolean isError) { if (mBiometricView != null) { mBiometricView.startTransitionToCredentialUI(isError); @@ -648,11 +633,11 @@ public class AuthContainerView extends LinearLayout } } - void animateAway(@AuthDialogCallback.DismissedReason int reason) { + void animateAway(@BiometricPrompt.DismissedReason int reason) { animateAway(true /* sendReason */, reason); } - private void animateAway(boolean sendReason, @AuthDialogCallback.DismissedReason int reason) { + private void animateAway(boolean sendReason, @BiometricPrompt.DismissedReason int reason) { if (mContainerState == STATE_ANIMATING_IN) { Log.w(TAG, "startDismiss(): waiting for onDialogAnimatedIn"); mContainerState = STATE_PENDING_DISMISS; @@ -732,7 +717,7 @@ public class AuthContainerView extends LinearLayout private void onDialogAnimatedIn() { if (mContainerState == STATE_PENDING_DISMISS) { Log.d(TAG, "onDialogAnimatedIn(): mPendingDismissDialog=true, dismissing now"); - animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); + animateAway(BiometricPrompt.DISMISSED_REASON_USER_CANCEL); return; } if (mContainerState == STATE_ANIMATING_OUT || mContainerState == STATE_GONE) { @@ -748,7 +733,6 @@ public class AuthContainerView extends LinearLayout } } - @Override public PromptViewModel getViewModel() { return mPromptViewModel; } @@ -776,7 +760,6 @@ public class AuthContainerView extends LinearLayout return lp; } - @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println(" isAttachedToWindow=" + isAttachedToWindow()); pw.println(" containerState=" + mContainerState); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index eee5f9e34317..68a282018ba4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -163,7 +163,7 @@ public class AuthController implements // TODO: These should just be saved from onSaveState private SomeArgs mCurrentDialogArgs; @VisibleForTesting - AuthDialog mCurrentDialog; + AuthContainerView mCurrentDialog; @NonNull private final WindowManager mWindowManager; @NonNull private final DisplayManager mDisplayManager; @@ -222,7 +222,7 @@ public class AuthController implements closeDialog(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, reasonString); } - private void closeDialog(@DismissedReason int reason, String reasonString) { + private void closeDialog(@BiometricPrompt.DismissedReason int reason, String reasonString) { if (isShowing()) { Log.i(TAG, "Close BP, reason :" + reasonString); mCurrentDialog.dismissWithoutCallback(true /* animate */); @@ -511,60 +511,14 @@ public class AuthController implements } @Override - public void onDismissed(@DismissedReason int reason, - @Nullable byte[] credentialAttestation, long requestId) { - + public void onDismissed(@BiometricPrompt.DismissedReason int reason, + @Nullable byte[] credentialAttestation, long requestId) { if (mCurrentDialog != null && requestId != mCurrentDialog.getRequestId()) { Log.w(TAG, "requestId doesn't match, skip onDismissed"); return; } - switch (reason) { - case AuthDialogCallback.DISMISSED_USER_CANCELED: - sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, - credentialAttestation); - break; - - case AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE: - sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_NEGATIVE, - credentialAttestation); - break; - - case AuthDialogCallback.DISMISSED_BUTTON_POSITIVE: - sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED, - credentialAttestation); - break; - - case AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED: - sendResultAndCleanUp( - BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRM_NOT_REQUIRED, - credentialAttestation); - break; - - case AuthDialogCallback.DISMISSED_ERROR: - sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_ERROR, - credentialAttestation); - break; - - case AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER: - sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED, - credentialAttestation); - break; - - case AuthDialogCallback.DISMISSED_CREDENTIAL_AUTHENTICATED: - sendResultAndCleanUp(BiometricPrompt.DISMISSED_REASON_CREDENTIAL_CONFIRMED, - credentialAttestation); - break; - - case AuthDialogCallback.DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS: - sendResultAndCleanUp( - BiometricPrompt.DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS, - credentialAttestation); - break; - default: - Log.e(TAG, "Unhandled reason: " + reason); - break; - } + sendResultAndCleanUp(reason, credentialAttestation); } @Override @@ -699,7 +653,7 @@ public class AuthController implements mUdfpsController.onAodInterrupt(screenX, screenY, major, minor); } - private void sendResultAndCleanUp(@DismissedReason int reason, + private void sendResultAndCleanUp(@BiometricPrompt.DismissedReason int reason, @Nullable byte[] credentialAttestation) { if (mReceiver == null) { Log.e(TAG, "sendResultAndCleanUp: Receiver is null"); @@ -1244,7 +1198,7 @@ public class AuthController implements final long requestId = args.argl2; // Create a new dialog but do not replace the current one yet. - final AuthDialog newDialog = buildDialog( + final AuthContainerView newDialog = buildDialog( mBackgroundExecutor, promptInfo, requireConfirmation, @@ -1327,7 +1281,7 @@ public class AuthController implements return mContext.createDisplayContext(display).getSystemService(WindowManager.class); } - private void onDialogDismissed(@DismissedReason int reason) { + private void onDialogDismissed(@BiometricPrompt.DismissedReason int reason) { if (DEBUG) Log.d(TAG, "onDialogDismissed: " + reason); if (mCurrentDialog == null) { Log.w(TAG, "Dialog already dismissed"); @@ -1361,7 +1315,7 @@ public class AuthController implements } } - protected AuthDialog buildDialog(@Background DelayableExecutor bgExecutor, + protected AuthContainerView buildDialog(@Background DelayableExecutor bgExecutor, PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds, String opPackageName, boolean skipIntro, long operationId, long requestId, @NonNull WakefulnessLifecycle wakefulnessLifecycle, @@ -1389,7 +1343,7 @@ public class AuthController implements @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { - final AuthDialog dialog = mCurrentDialog; + final AuthContainerView dialog = mCurrentDialog; pw.println(" mCachedDisplayInfo=" + mCachedDisplayInfo); pw.println(" mScaleFactor=" + mScaleFactor); pw.println(" fingerprintSensorLocationInNaturalOrientation=" diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java deleted file mode 100644 index 861191671ba9..000000000000 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.biometrics; - -import android.hardware.biometrics.BiometricAuthenticator.Modality; -import android.view.WindowManager; - -import com.android.systemui.Dumpable; -import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel; - -/** - * Interface for the biometric dialog UI. - * - * TODO(b/287311775): remove along with legacy controller once flag is removed - */ -@Deprecated -public interface AuthDialog extends Dumpable { - - /** - * Parameters used when laying out {@link AuthBiometricView}, its subclasses, and - * {@link AuthPanelController}. - */ - class LayoutParams { - public final int mMediumHeight; - public final int mMediumWidth; - - public LayoutParams(int mediumWidth, int mediumHeight) { - mMediumWidth = mediumWidth; - mMediumHeight = mediumHeight; - } - } - - /** - * Show the dialog. - * @param wm - */ - void show(WindowManager wm); - - /** - * Dismiss the dialog without sending a callback. - */ - void dismissWithoutCallback(boolean animate); - - /** - * Dismiss the dialog. Animate away. - */ - void dismissFromSystemServer(); - - /** - * Biometric authenticated. May be pending user confirmation, or completed. - */ - void onAuthenticationSucceeded(@Modality int modality); - - /** - * Authentication failed (reject, timeout). Dialog stays showing. - * @param modality sensor modality that triggered the error - * @param failureReason message - */ - void onAuthenticationFailed(@Modality int modality, String failureReason); - - /** - * Authentication rejected, or help message received. - * @param modality sensor modality that triggered the help message - * @param help message - */ - void onHelp(@Modality int modality, String help); - - /** - * Authentication failed. Dialog going away. - * @param modality sensor modality that triggered the error - * @param error message - */ - void onError(@Modality int modality, String error); - - /** UDFPS pointer down event. */ - void onPointerDown(); - - /** - * Get the client's package name - */ - String getOpPackageName(); - - /** - * Get the class name of ConfirmDeviceCredentialActivity. Returns null if the direct caller is - * not ConfirmDeviceCredentialActivity. - */ - String getClassNameIfItIsConfirmDeviceCredentialActivity(); - - /** The requestId of the underlying operation within the framework. */ - long getRequestId(); - - /** - * Animate to credential UI. Typically called after biometric is locked out. - */ - void animateToCredentialUI(boolean isError); - - /** - * @return true if device credential is allowed. - */ - boolean isAllowDeviceCredentials(); - - /** - * Called when the device's orientation changed and the dialog may need to do another - * layout. This is most relevant to UDFPS since configuration changes are not sent by - * the framework in equivalent cases (landscape to reverse landscape) but the dialog - * must remain fixed on the physical sensor location. - */ - void onOrientationChanged(); - - PromptViewModel getViewModel(); -} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java index 024c6eaa75bb..31c63d3c57e0 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogCallback.java @@ -16,40 +16,20 @@ package com.android.systemui.biometrics; -import android.annotation.IntDef; import android.annotation.Nullable; +import android.hardware.biometrics.BiometricPrompt; /** * Callback interface for dialog views. These should be implemented by the controller (e.g. * FingerprintDialogImpl) and passed into their views (e.g. FingerprintDialogView). */ public interface AuthDialogCallback { - - int DISMISSED_USER_CANCELED = 1; - int DISMISSED_BUTTON_NEGATIVE = 2; - int DISMISSED_BUTTON_POSITIVE = 3; - int DISMISSED_BIOMETRIC_AUTHENTICATED = 4; - int DISMISSED_ERROR = 5; - int DISMISSED_BY_SYSTEM_SERVER = 6; - int DISMISSED_CREDENTIAL_AUTHENTICATED = 7; - int DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS = 8; - - @IntDef({DISMISSED_USER_CANCELED, - DISMISSED_BUTTON_NEGATIVE, - DISMISSED_BUTTON_POSITIVE, - DISMISSED_BIOMETRIC_AUTHENTICATED, - DISMISSED_ERROR, - DISMISSED_BY_SYSTEM_SERVER, - DISMISSED_CREDENTIAL_AUTHENTICATED, - DISMISSED_BUTTON_CONTENT_VIEW_MORE_OPTIONS}) - @interface DismissedReason {} - /** * Invoked when the dialog is dismissed - * @param reason + * @param reason - the {@link BiometricPrompt.DismissedReason} for dismissing * @param credentialAttestation the HAT received from LockSettingsService upon verification */ - void onDismissed(@DismissedReason int reason, + void onDismissed(@BiometricPrompt.DismissedReason int reason, @Nullable byte[] credentialAttestation, long requestId); /** diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java index 4ac5a12dae03..f7efabac0d14 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricNotificationDialogFactory.java @@ -32,6 +32,7 @@ import android.util.Log; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.res.R; +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor; import com.android.systemui.statusbar.phone.SystemUIDialog; import javax.inject.Inject; @@ -44,6 +45,7 @@ public class BiometricNotificationDialogFactory { private static final String TAG = "BiometricNotificationDialogFactory"; private final Resources mResources; private final SystemUIDialog.Factory mSystemUIDialogFactory; + private final ShadeDialogContextInteractor mDialogContextInteractor; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; @@ -51,10 +53,12 @@ public class BiometricNotificationDialogFactory { BiometricNotificationDialogFactory( @Main Resources resources, SystemUIDialog.Factory systemUIDialogFactory, + ShadeDialogContextInteractor shadeDialogContextInteractor, @Nullable FingerprintManager fingerprintManager, @Nullable FaceManager faceManager) { mResources = resources; mSystemUIDialogFactory = systemUIDialogFactory; + mDialogContextInteractor = shadeDialogContextInteractor; mFingerprintManager = fingerprintManager; mFaceManager = faceManager; } @@ -62,7 +66,8 @@ public class BiometricNotificationDialogFactory { Dialog createReenrollDialog( int userId, ActivityStarter activityStarter, BiometricSourceType biometricSourceType, boolean isReenrollForced) { - SystemUIDialog sysuiDialog = mSystemUIDialogFactory.create(); + SystemUIDialog sysuiDialog = + mSystemUIDialogFactory.create(mDialogContextInteractor.getContext()); if (biometricSourceType == BiometricSourceType.FACE) { sysuiDialog.setTitle(mResources.getString(R.string.face_re_enroll_dialog_title)); sysuiDialog.setMessage(mResources.getString(R.string.face_re_enroll_dialog_content)); @@ -90,7 +95,8 @@ public class BiometricNotificationDialogFactory { } private Dialog createReenrollFailureDialog(BiometricSourceType biometricType) { - final SystemUIDialog sysuiDialog = mSystemUIDialogFactory.create(); + final SystemUIDialog sysuiDialog = + mSystemUIDialogFactory.create(mDialogContextInteractor.getContext()); if (biometricType == BiometricSourceType.FACE) { sysuiDialog.setMessage(mResources.getString( diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index fd11fa5d3e80..88694ae6db51 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -94,6 +94,7 @@ import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.shade.ShadeDisplayAware; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.VibratorHelper; @@ -656,9 +657,9 @@ public class UdfpsController implements DozeReceiver, Dumpable { } @Inject - public UdfpsController(@NonNull Context context, + public UdfpsController(@NonNull @Main Context context, @NonNull Execution execution, - @NonNull LayoutInflater inflater, + @NonNull @ShadeDisplayAware LayoutInflater inflater, @Nullable FingerprintManager fingerprintManager, @NonNull ViewCaptureAwareWindowManager viewCaptureAwareWindowManager, @NonNull StatusBarStateController statusBarStateController, @@ -676,7 +677,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { @NonNull KeyguardStateController keyguardStateController, @NonNull DisplayManager displayManager, @Main Handler mainHandler, - @NonNull ConfigurationController configurationController, + @NonNull @Main ConfigurationController configurationController, @NonNull SystemClock systemClock, @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, @NonNull SystemUIDialogManager dialogManager, diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt index eebcf0b0f0c1..576acd2e5304 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt @@ -383,6 +383,11 @@ constructor( actionIcon.setImageResource(item.actionIconRes) actionIcon.drawable?.setTint(tintColor) + actionIconView.contentDescription = + resources.getString( + R.string.accessibility_bluetooth_device_settings_gear_with_name, + item.deviceName, + ) divider.setBackgroundColor(tintColor) diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt index ff2d9efa1b58..1c9cf8d14f74 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt @@ -31,6 +31,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.UiEventLogger import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast +import com.android.settingslib.volume.domain.interactor.AudioModeInteractor import com.android.systemui.Prefs import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogTransitionAnimator @@ -71,6 +72,7 @@ constructor( private val bluetoothStateInteractor: BluetoothStateInteractor, private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor, private val audioSharingInteractor: AudioSharingInteractor, + private val audioModeInteractor: AudioModeInteractor, private val audioSharingButtonViewModelFactory: AudioSharingButtonViewModel.Factory, private val bluetoothDeviceMetadataInteractor: BluetoothDeviceMetadataInteractor, private val dialogTransitionAnimator: DialogTransitionAnimator, @@ -167,6 +169,7 @@ constructor( // the device item list and animate the progress bar. merge( deviceItemInteractor.deviceItemUpdateRequest, + audioModeInteractor.isOngoingCall, bluetoothDeviceMetadataInteractor.metadataUpdate, if ( audioSharingInteractor.audioSharingAvailable() && diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt index 095e6e741584..bfbc27d3a086 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt @@ -18,7 +18,6 @@ package com.android.systemui.bluetooth.qsdialog import android.bluetooth.BluetoothDevice import android.content.Context -import android.media.AudioManager import com.android.settingslib.bluetooth.BluetoothUtils import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.bluetooth.LocalBluetoothManager @@ -43,7 +42,7 @@ abstract class DeviceItemFactory { abstract fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean @@ -51,8 +50,8 @@ abstract class DeviceItemFactory { fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, - ): Boolean = isFilterMatched(context, cachedDevice, audioManager, false) + isOngoingCall: Boolean, + ): Boolean = isFilterMatched(context, cachedDevice, isOngoingCall, false) abstract fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem @@ -88,11 +87,11 @@ internal open class ActiveMediaDeviceItemFactory : DeviceItemFactory() { override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return BluetoothUtils.isActiveMediaDevice(cachedDevice) && - BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, audioManager) + BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, isOngoingCall) } override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { @@ -113,10 +112,11 @@ internal class AudioSharingMediaDeviceItemFactory( override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return audioSharingAvailable && + !isOngoingCall && BluetoothUtils.hasConnectedBroadcastSource(cachedDevice, localBluetoothManager) } @@ -140,11 +140,12 @@ internal class AvailableAudioSharingMediaDeviceItemFactory( override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return audioSharingAvailable && - super.isFilterMatched(context, cachedDevice, audioManager, true) && + !isOngoingCall && + super.isFilterMatched(context, cachedDevice, false, true) && BluetoothUtils.isAvailableAudioSharingMediaBluetoothDevice( cachedDevice, localBluetoothManager, @@ -170,7 +171,7 @@ internal class ActiveHearingDeviceItemFactory : ActiveMediaDeviceItemFactory() { override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return BluetoothUtils.isActiveMediaDevice(cachedDevice) && @@ -182,11 +183,11 @@ open class AvailableMediaDeviceItemFactory : DeviceItemFactory() { override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return !BluetoothUtils.isActiveMediaDevice(cachedDevice) && - BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, audioManager) + BluetoothUtils.isAvailableMediaBluetoothDevice(cachedDevice, isOngoingCall) } override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { @@ -206,7 +207,7 @@ internal class AvailableHearingDeviceItemFactory : AvailableMediaDeviceItemFacto override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return !BluetoothUtils.isActiveMediaDevice(cachedDevice) && @@ -218,14 +219,14 @@ internal class ConnectedDeviceItemFactory : DeviceItemFactory() { override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) { !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) && - BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager) + BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, isOngoingCall) } else { - BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager) + BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, isOngoingCall) } } @@ -246,7 +247,7 @@ internal open class SavedDeviceItemFactory : DeviceItemFactory() { override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) { @@ -275,7 +276,7 @@ internal class SavedHearingDeviceItemFactory : SavedDeviceItemFactory() { override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ): Boolean { return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) { diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt index 1e0ba8e75714..b606c19b3503 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractor.kt @@ -19,10 +19,10 @@ package com.android.systemui.bluetooth.qsdialog import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothDevice import android.content.Context -import android.media.AudioManager import com.android.settingslib.bluetooth.BluetoothCallback import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.settingslib.bluetooth.LocalBluetoothManager +import com.android.settingslib.volume.domain.interactor.AudioModeInteractor import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton @@ -39,6 +39,7 @@ import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.isActive @@ -51,7 +52,6 @@ class DeviceItemInteractor constructor( private val bluetoothTileDialogRepository: BluetoothTileDialogRepository, private val audioSharingInteractor: AudioSharingInteractor, - private val audioManager: AudioManager, private val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter(), private val localBluetoothManager: LocalBluetoothManager?, private val systemClock: SystemClock, @@ -60,6 +60,7 @@ constructor( private val deviceItemDisplayPriority: List<@JvmSuppressWildcards DeviceItemType>, @Application private val coroutineScope: CoroutineScope, @Background private val backgroundDispatcher: CoroutineDispatcher, + private val audioModeInteractor: AudioModeInteractor, ) { private val mutableDeviceItemUpdate: MutableSharedFlow<List<DeviceItem>> = @@ -118,8 +119,12 @@ constructor( internal suspend fun updateDeviceItems(context: Context, trigger: DeviceFetchTrigger) { withContext(backgroundDispatcher) { + if (!isActive) { + return@withContext + } val start = systemClock.elapsedRealtime() val audioSharingAvailable = audioSharingInteractor.audioSharingAvailable() + val isOngoingCall = audioModeInteractor.isOngoingCall.first() val deviceItems = bluetoothTileDialogRepository.cachedDevices .mapNotNull { cachedDevice -> @@ -128,7 +133,7 @@ constructor( it.isFilterMatched( context, cachedDevice, - audioManager, + isOngoingCall, audioSharingAvailable, ) } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt index 149efcdcbb8a..3ef50f68cba4 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/constants/KeyguardBouncerConstants.kt @@ -87,6 +87,14 @@ private fun <T> c(old: T, new: T): T { } } +object PatternBouncerConstants { + object ColorId { + @JvmField val dotColor = colors.materialColorOnSurfaceVariant + @JvmField val activatedDotColor = colors.materialColorOnPrimary + @JvmField val pathColor = colors.materialColorPrimary + } +} + object PinBouncerConstants { @JvmField val pinShapes = c(old = R.array.bouncer_pin_shapes, new = R.array.updated_bouncer_pin_shapes) diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt index 434a9ce58c3b..7d8945a5b4a7 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt @@ -191,7 +191,6 @@ object KeyguardBouncerViewBinder { .filter { it == EXPANSION_VISIBLE } .collect { securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON) - view.announceForAccessibility(securityContainerController.title) } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt index 0a9bd4214a12..bf4445ba18db 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt @@ -151,5 +151,7 @@ constructor( override fun instantlyShowOverlay(overlay: OverlayKey) = Unit override fun instantlyHideOverlay(overlay: OverlayKey) = Unit + + override fun freezeAndAnimateToCurrentState() = Unit } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt index ca49de3b1510..a84c45732169 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/shared/model/CommunalTransitionKeys.kt @@ -31,4 +31,6 @@ object CommunalTransitionKeys { val ToEditMode = TransitionKey("ToEditMode") /** Transition to the glanceable hub after exiting edit mode */ val FromEditMode = TransitionKey("FromEditMode") + /** Swipes the glanceable hub in/out of view */ + val Swipe = TransitionKey("Swipe") } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt index 2169881d11c5..6473b1c30586 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt @@ -237,7 +237,15 @@ constructor( with(mediaHost) { expansion = MediaHostState.EXPANDED expandedMatchesParentHeight = true - showsOnlyActiveMedia = false + if (v2FlagEnabled()) { + // Only show active media to match lock screen, not resumable media, which can + // persist + // for up to 2 days. + showsOnlyActiveMedia = true + } else { + // Maintain old behavior on tablet until V2 flag rolls out. + showsOnlyActiveMedia = false + } falsingProtectionNeeded = false disablePagination = true init(MediaHierarchyManager.LOCATION_COMMUNAL_HUB) @@ -359,7 +367,13 @@ constructor( /** See [CommunalSettingsInteractor.isV2FlagEnabled] */ fun v2FlagEnabled(): Boolean = communalSettingsInteractor.isV2FlagEnabled() - fun swipeToHubEnabled(): Boolean = swipeToHub + val swipeToHubEnabled: StateFlow<Boolean> by lazy { + if (v2FlagEnabled()) { + communalInteractor.shouldShowCommunal + } else { + MutableStateFlow(swipeToHub) + } + } companion object { const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 3c68e3a09f02..a25faa3a7aec 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -56,6 +56,7 @@ import com.android.systemui.reardisplay.RearDisplayModule; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsImplementation; import com.android.systemui.recents.RecentsModule; +import com.android.systemui.rotationlock.DeviceStateAutoRotateModule; import com.android.systemui.rotationlock.RotationLockModule; import com.android.systemui.rotationlock.RotationLockNewModule; import com.android.systemui.scene.SceneContainerFrameworkModule; @@ -132,6 +133,7 @@ import javax.inject.Named; CollapsedStatusBarFragmentStartableModule.class, ConnectingDisplayViewModel.StartableModule.class, DefaultBlueprintModule.class, + DeviceStateAutoRotateModule.class, EmergencyGestureModule.class, GestureModule.class, HeadsUpModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index fe5a82cb5b8c..f8cf6b007041 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -105,6 +105,7 @@ import com.android.systemui.qs.footer.dagger.FooterActionsModule; import com.android.systemui.recents.Recents; import com.android.systemui.recordissue.RecordIssueModule; import com.android.systemui.retail.RetailModeModule; +import com.android.systemui.rotationlock.DeviceStateAutoRotateModule.BoundsDeviceStateAutoRotateModule; import com.android.systemui.scene.shared.model.SceneContainerConfig; import com.android.systemui.scene.shared.model.SceneDataSource; import com.android.systemui.scene.shared.model.SceneDataSourceDelegator; @@ -145,6 +146,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.phone.ConfigurationControllerModule; import com.android.systemui.statusbar.phone.LetterboxModule; import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule; +import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.PolicyModule; import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController; @@ -391,6 +393,11 @@ public abstract class SystemUIModule { @BindsOptionalOf abstract LockscreenContent optionalLockscreenContent(); + @BindsOptionalOf + @BoundsDeviceStateAutoRotateModule + abstract Optional<DeviceStateRotationLockSettingController> + optionalDeviceStateRotationLockSettingController(); + @SysUISingleton @Binds abstract SystemClock bindSystemClock(SystemClockImpl systemClock); @@ -466,6 +473,16 @@ public abstract class SystemUIModule { return new SceneDataSourceDelegator(applicationScope, config); } + @Provides + @SysUISingleton + static Optional<DeviceStateRotationLockSettingController> + provideDeviceStateRotationLockSettingController( + @BoundsDeviceStateAutoRotateModule + Optional<Optional<DeviceStateRotationLockSettingController>> optionalOfOptional + ) { + return optionalOfOptional.orElseGet(Optional::empty); + } + @Binds abstract SceneDataSource bindSceneDataSource(SceneDataSourceDelegator delegator); diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/TouchpadTutorialScreensProvider.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/TouchpadTutorialScreensProvider.kt index bd3e771f40bc..7d2492a41e82 100644 --- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/TouchpadTutorialScreensProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/TouchpadTutorialScreensProvider.kt @@ -20,7 +20,9 @@ import androidx.compose.runtime.Composable interface TouchpadTutorialScreensProvider { - @Composable fun BackGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) + @Composable + fun BackGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit, isAutoProceed: Boolean) - @Composable fun HomeGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) + @Composable + fun HomeGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit, isAutoProceed: Boolean) } diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt index b712fdeaf623..0d57a57c3416 100644 --- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/domain/interactor/TutorialSchedulerInteractor.kt @@ -102,10 +102,9 @@ constructor( } // This flow is used by the notification updater once an initial notification is launched. It - // listens to the device connection changes for both keyboard and touchpad. When either of the - // device is disconnected, resolve the tutorial type base on the latest connection state. - // Dropping the initial state because it's the existing notification. Filtering out BOTH because - // we only care about disconnections. + // listens to the changes of keyboard and touchpad connection and resolve the tutorial type base + // on the latest connection state. + // Dropping the initial state because it represents the existing notification. val tutorialTypeUpdates: Flow<TutorialType> = keyboardRepository.isAnyKeyboardConnected .combine(touchpadRepository.isAnyTouchpadConnected, ::Pair) @@ -118,7 +117,6 @@ constructor( } } .drop(1) - .filter { it != TutorialType.BOTH } private suspend fun waitForDeviceConnection(deviceType: DeviceType) = isAnyDeviceConnected[deviceType]!!.filter { it }.first() diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt index 8cbcba2c3b1c..ee875c484ca6 100644 --- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt @@ -137,6 +137,7 @@ fun ActionTutorialContent( onDoneButtonClicked = onDoneButtonClicked, modifier = Modifier.padding(horizontal = 60.dp).graphicsLayer { alpha = buttonAlpha }, enabled = actionState is Finished, + isNext = config.hasNextButton, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialComponents.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialComponents.kt index 202dba357d45..d92e48e18801 100644 --- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialComponents.kt +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialComponents.kt @@ -32,6 +32,7 @@ fun DoneButton( onDoneButtonClicked: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, + isNext: Boolean = false, ) { Row( horizontalArrangement = Arrangement.End, @@ -39,7 +40,10 @@ fun DoneButton( modifier = modifier.fillMaxWidth(), ) { Button(onClick = onDoneButtonClicked, enabled = enabled) { - Text(stringResource(R.string.touchpad_tutorial_done_button)) + val text = + if (isNext) R.string.touchpad_tutorial_next_button + else R.string.touchpad_tutorial_done_button + Text(stringResource(text)) } } } diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt index eda23a51a1ae..65adc148b6ae 100644 --- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/TutorialScreenConfig.kt @@ -28,6 +28,7 @@ data class TutorialScreenConfig( val colors: Colors, val strings: Strings, val animations: Animations, + val hasNextButton: Boolean = false, ) { data class Colors( diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt index 639e9b1805be..086705fbd7ba 100644 --- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/view/KeyboardTouchpadTutorialActivity.kt @@ -93,17 +93,29 @@ constructor( } } } + val entryPointExtra = intent.getStringExtra(INTENT_TUTORIAL_ENTRY_POINT_KEY) + val isAutoProceed = + if (entryPointExtra == null) true + else entryPointExtra.equals(INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER) + val scopeExtra = intent.getStringExtra(INTENT_TUTORIAL_SCOPE_KEY) + val isScopeAll = INTENT_TUTORIAL_SCOPE_ALL.equals(scopeExtra) setContent { - PlatformTheme { KeyboardTouchpadTutorialContainer(vm, touchpadTutorialScreensProvider) } + PlatformTheme { + KeyboardTouchpadTutorialContainer( + vm, + touchpadTutorialScreensProvider, + isAutoProceed, + isScopeAll, + ) + } } if (savedInstanceState == null) { logger.logOpenTutorial(TutorialContext.KEYBOARD_TOUCHPAD_TUTORIAL) - val entryPointExtra = intent.getStringExtra(INTENT_TUTORIAL_ENTRY_POINT_KEY) val tutorialTypeExtra = intent.getStringExtra(INTENT_TUTORIAL_SCOPE_KEY) metricsLogger.logPeripheralTutorialLaunched(entryPointExtra, tutorialTypeExtra) // We only update launched info when the tutorial is triggered by the scheduler - if (entryPointExtra.equals(INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER)) + if (INTENT_TUTORIAL_ENTRY_POINT_SCHEDULER.equals(entryPointExtra)) updateLaunchInfo(tutorialTypeExtra) } } @@ -124,17 +136,27 @@ constructor( fun KeyboardTouchpadTutorialContainer( vm: KeyboardTouchpadTutorialViewModel, touchpadScreens: Optional<TouchpadTutorialScreensProvider>, + isAutoProceed: Boolean = false, + isScopeAll: Boolean = false, ) { val activeScreen by vm.screen.collectAsStateWithLifecycle(STARTED) when (activeScreen) { BACK_GESTURE -> touchpadScreens .get() - .BackGesture(onDoneButtonClicked = vm::onDoneButtonClicked, onBack = vm::onBack) + .BackGesture( + onDoneButtonClicked = vm::onDoneButtonClicked, + onBack = vm::onBack, + isAutoProceed = isAutoProceed, + ) HOME_GESTURE -> touchpadScreens .get() - .HomeGesture(onDoneButtonClicked = vm::onDoneButtonClicked, onBack = vm::onBack) + .HomeGesture( + onDoneButtonClicked = vm::onDoneButtonClicked, + onBack = vm::onBack, + isAutoProceed = isScopeAll, + ) ACTION_KEY -> ActionKeyTutorialScreen( onDoneButtonClicked = vm::onDoneButtonClicked, diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt index 0908e3b5bf85..a779c4c998a7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/repository/InputGestureMaps.kt @@ -31,7 +31,6 @@ import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION -import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS import android.hardware.input.KeyGestureEvent.KEY_GESTURE_TYPE_RECENT_APPS_SWITCHER @@ -67,7 +66,6 @@ class InputGestureMaps @Inject constructor(private val context: Context) { KEY_GESTURE_TYPE_OPEN_SHORTCUT_HELPER to System, KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL to System, KEY_GESTURE_TYPE_LOCK_SCREEN to System, - KEY_GESTURE_TYPE_OPEN_NOTES to System, KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to System, KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to System, KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to System, @@ -113,7 +111,6 @@ class InputGestureMaps @Inject constructor(private val context: Context) { R.string.shortcut_helper_category_system_controls, KEY_GESTURE_TYPE_LOCK_SCREEN to R.string.shortcut_helper_category_system_controls, KEY_GESTURE_TYPE_ALL_APPS to R.string.shortcut_helper_category_system_controls, - KEY_GESTURE_TYPE_OPEN_NOTES to R.string.shortcut_helper_category_system_apps, KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to R.string.shortcut_helper_category_system_apps, KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to R.string.shortcut_helper_category_system_apps, @@ -173,7 +170,6 @@ class InputGestureMaps @Inject constructor(private val context: Context) { R.string.group_system_access_notification_shade, KEY_GESTURE_TYPE_LOCK_SCREEN to R.string.group_system_lock_screen, KEY_GESTURE_TYPE_ALL_APPS to R.string.group_system_access_all_apps_search, - KEY_GESTURE_TYPE_OPEN_NOTES to R.string.group_system_quick_memo, KEY_GESTURE_TYPE_LAUNCH_SYSTEM_SETTINGS to R.string.group_system_access_system_settings, KEY_GESTURE_TYPE_LAUNCH_ASSISTANT to R.string.group_system_access_google_assistant, KEY_GESTURE_TYPE_LAUNCH_VOICE_ASSISTANT to diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt index 464201f6ec12..b787fc2a2b17 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/MultitaskingShortcutsSource.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyboard.shortcut.data.source import android.content.Context import android.content.res.Resources import android.view.KeyEvent.KEYCODE_D +import android.view.KeyEvent.KEYCODE_DPAD_DOWN import android.view.KeyEvent.KEYCODE_DPAD_LEFT import android.view.KeyEvent.KEYCODE_DPAD_RIGHT import android.view.KeyEvent.KEYCODE_DPAD_UP @@ -73,6 +74,15 @@ constructor(@Main private val resources: Resources, @Application private val con command(META_META_ON or META_CTRL_ON, KEYCODE_DPAD_UP) } ) + if (DesktopModeStatus.canEnterDesktopMode(context)) { + // Switch to desktop view + // - Meta + Ctrl + Down arrow + add( + shortcutInfo(resources.getString(R.string.system_multitasking_desktop_view)) { + command(META_META_ON or META_CTRL_ON, KEYCODE_DPAD_DOWN) + } + ) + } if (enableMoveToNextDisplayShortcut()) { // Move a window to the next display: // - Meta + Ctrl + D diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt index 8bed8537b6c5..a7375f7e7efc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/data/source/SystemShortcutsSource.kt @@ -178,11 +178,6 @@ constructor(@Main private val resources: Resources, private val inputManager: In private fun systemAppsShortcuts() = listOf( - // Pull up Notes app for quick memo: - // - Meta + Ctrl + N - shortcutInfo(resources.getString(R.string.group_system_quick_memo)) { - command(META_META_ON or META_CTRL_ON, KEYCODE_N) - }, // Access system settings: // - Meta + I shortcutInfo(resources.getString(R.string.group_system_access_system_settings)) { diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt index 61d11f4df5e0..f89421f9b73e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/domain/interactor/ShortcutHelperCategoriesInteractor.kt @@ -17,19 +17,16 @@ package com.android.systemui.keyboard.shortcut.domain.interactor import android.content.Context -import android.view.KeyEvent.META_META_ON import com.android.systemui.Flags.keyboardShortcutHelperShortcutCustomizer import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyboard.shortcut.data.repository.ShortcutCategoriesRepository -import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys -import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys.metaModifierIconResId +import com.android.systemui.keyboard.shortcut.extensions.toContentDescription import com.android.systemui.keyboard.shortcut.qualifiers.CustomShortcutCategories import com.android.systemui.keyboard.shortcut.qualifiers.DefaultShortcutCategories import com.android.systemui.keyboard.shortcut.shared.model.Shortcut import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCommand -import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory import com.android.systemui.res.R import dagger.Lazy @@ -105,8 +102,6 @@ constructor( context.getString(R.string.shortcut_helper_key_combinations_and_conjunction) val orConjunction = context.getString(R.string.shortcut_helper_key_combinations_or_separator) - val forwardSlash = - context.getString(R.string.shortcut_helper_key_combinations_forward_slash) return buildString { append("$label, $pressKey") commands.forEachIndexed { i, shortcutCommand -> @@ -117,29 +112,7 @@ constructor( if (j > 0) { append(" $andConjunction") } - if (shortcutKey is ShortcutKey.Text) { - // Special handling for "/" as TalkBack will not read punctuation by - // default. - if (shortcutKey.value.equals("/")) { - append(" $forwardSlash") - } else { - append(" ${shortcutKey.value}") - } - } else if (shortcutKey is ShortcutKey.Icon.ResIdIcon) { - val keyLabel = - if (shortcutKey.drawableResId == metaModifierIconResId) { - ShortcutHelperKeys.modifierLabels[META_META_ON] - } else { - val keyCode = - ShortcutHelperKeys.keyIcons.entries - .firstOrNull { it.value == shortcutKey.drawableResId } - ?.key - ShortcutHelperKeys.specialKeyLabels[keyCode] - } - if (keyLabel != null) { - append(" ${keyLabel.invoke(context)}") - } - } // No-Op when shortcutKey is ShortcutKey.Icon.DrawableIcon + shortcutKey.toContentDescription(context)?.let { append(" $it") } } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/ShortcutKeyExtensions.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/ShortcutKeyExtensions.kt new file mode 100644 index 000000000000..5637747d5aba --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/extensions/ShortcutKeyExtensions.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyboard.shortcut.extensions + +import android.content.Context +import android.view.KeyEvent.META_META_ON +import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys +import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperKeys.metaModifierIconResId +import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey +import com.android.systemui.res.R + +fun ShortcutKey.toContentDescription(context: Context): String? { + val forwardSlash = context.getString(R.string.shortcut_helper_key_combinations_forward_slash) + when (this) { + is ShortcutKey.Text -> { + // Special handling for "/" as TalkBack will not read punctuation by + // default. + return if (this.value == "/") { + forwardSlash + } else { + this.value + } + } + + is ShortcutKey.Icon.ResIdIcon -> { + val keyLabel = + if (this.drawableResId == metaModifierIconResId) { + ShortcutHelperKeys.modifierLabels[META_META_ON] + } else { + val keyCode = + ShortcutHelperKeys.keyIcons.entries + .firstOrNull { it.value == this.drawableResId } + ?.key + ShortcutHelperKeys.specialKeyLabels[keyCode] + } + + if (keyLabel != null) { + return keyLabel.invoke(context) + } + } + + is ShortcutKey.Icon.DrawableIcon -> { + // No-Op when shortcutKey is ShortcutKey.Icon.DrawableIcon + } + } + + return null +} diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt index 66e45056989d..7e0fa2f125b0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt @@ -60,6 +60,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.LiveRegionMode import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.hideFromAccessibility import androidx.compose.ui.semantics.liveRegion import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight @@ -127,6 +128,7 @@ private fun AddShortcutDialog( shouldShowError = uiState.errorMessage.isNotEmpty(), onShortcutKeyCombinationSelected = onShortcutKeyCombinationSelected, pressedKeys = uiState.pressedKeys, + contentDescription = uiState.pressedKeysDescription, onConfirmSetShortcut = onConfirmSetShortcut, onClearSelectedKeyCombination = onClearSelectedKeyCombination, ) @@ -267,6 +269,7 @@ private fun SelectedKeyCombinationContainer( shouldShowError: Boolean, onShortcutKeyCombinationSelected: (KeyEvent) -> Boolean, pressedKeys: List<ShortcutKey>, + contentDescription: String, onConfirmSetShortcut: () -> Unit, onClearSelectedKeyCombination: () -> Unit, ) { @@ -313,6 +316,7 @@ private fun SelectedKeyCombinationContainer( } else { null }, + contentDescription = contentDescription, ) } @@ -331,8 +335,7 @@ private fun ErrorIcon(shouldShowError: Boolean) { @Composable private fun PressedKeysTextContainer(pressedKeys: List<ShortcutKey>) { Row( - modifier = - Modifier.semantics(mergeDescendants = true) { liveRegion = LiveRegionMode.Polite }, + modifier = Modifier.semantics { hideFromAccessibility() }, verticalAlignment = Alignment.CenterVertically, ) { pressedKeys.forEachIndexed { keyIndex, key -> @@ -495,6 +498,7 @@ private fun OutlinedInputField( trailingIcon: @Composable () -> Unit, isError: Boolean, modifier: Modifier = Modifier, + contentDescription: String, ) { OutlinedTextField( value = "", @@ -502,7 +506,10 @@ private fun OutlinedInputField( placeholder = if (content == null) placeholder else null, prefix = content, singleLine = true, - modifier = modifier, + modifier = + modifier.semantics(mergeDescendants = true) { + this.contentDescription = contentDescription + }, trailingIcon = trailingIcon, colors = OutlinedTextFieldDefaults.colors() diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt index 36c5ae0717be..688573df9ee7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/model/ShortcutCustomizationUiState.kt @@ -24,6 +24,7 @@ sealed interface ShortcutCustomizationUiState { val errorMessage: String = "", val defaultCustomShortcutModifierKey: ShortcutKey.Icon.ResIdIcon, val pressedKeys: List<ShortcutKey> = emptyList(), + val pressedKeysDescription: String = "", ) : ShortcutCustomizationUiState data object DeleteShortcutDialog : ShortcutCustomizationUiState diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt index f4ba99c6a394..aeedc4b7d618 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/viewmodel/ShortcutCustomizationViewModel.kt @@ -26,6 +26,7 @@ import androidx.compose.ui.input.key.nativeKeyCode import androidx.compose.ui.input.key.type import com.android.systemui.keyboard.shared.model.ShortcutCustomizationRequestResult import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutCustomizationInteractor +import com.android.systemui.keyboard.shortcut.extensions.toContentDescription import com.android.systemui.keyboard.shortcut.shared.model.KeyCombination import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCustomizationRequestInfo import com.android.systemui.keyboard.shortcut.shared.model.ShortcutKey @@ -185,7 +186,11 @@ constructor( _shortcutCustomizationUiState.update { uiState -> if (uiState is AddShortcutDialog) { - uiState.copy(pressedKeys = keys, errorMessage = errorMessage) + uiState.copy( + pressedKeys = keys, + errorMessage = errorMessage, + pressedKeysDescription = getAccessibilityDescForPressedKeys(keys), + ) } else { uiState } @@ -193,11 +198,25 @@ constructor( } } + private fun getAccessibilityDescForPressedKeys(keys: List<ShortcutKey>): String { + val andConjunction = + context.getString(R.string.shortcut_helper_key_combinations_and_conjunction) + return buildString { + keys.forEach { key -> + key.toContentDescription(context)?.let { + if (isNotEmpty()) { + append(", $andConjunction ") + } + append(it) + } + } + } + } + private suspend fun getErrorMessageForPressedKeys(keys: List<ShortcutKey>): String { return if (keys.isEmpty() or isSelectedKeyCombinationAvailable()) { "" - } - else { + } else { context.getString(R.string.shortcut_customizer_key_combination_in_use_error_message) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt index 80bdc65f9b97..f69229213690 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt @@ -25,11 +25,17 @@ import kotlinx.coroutines.flow.MutableStateFlow class LockscreenSceneTransitionRepository @Inject constructor() { /** - * This [KeyguardState] will indicate which sub state within KTF should be navigated to when the - * next transition into the Lockscreen scene is started. It will be consumed exactly once and - * after that the state will be set back to [DEFAULT_STATE]. + * This [KeyguardState] will indicate which sub-state within KTF should be navigated to next. + * + * This can be either starting a transition to the `Lockscreen` scene or cancelling a transition + * from the `Lockscreen` scene and returning back to it. + * + * A `null` value means that no explicit target state was set and therefore the [DEFAULT_STATE] + * should be used. + * + * Once consumed, this state should be reset to `null`. */ - val nextLockscreenTargetState: MutableStateFlow<KeyguardState> = MutableStateFlow(DEFAULT_STATE) + val nextLockscreenTargetState: MutableStateFlow<KeyguardState?> = MutableStateFlow(null) companion object { val DEFAULT_STATE = KeyguardState.LOCKSCREEN diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt index 4ad04bef6836..ef06a85bd0d9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt @@ -20,6 +20,10 @@ import android.animation.ValueAnimator import android.util.Log import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main @@ -54,6 +58,9 @@ constructor( keyguardOcclusionInteractor: KeyguardOcclusionInteractor, val deviceEntryRepository: DeviceEntryRepository, private val wakeToGoneInteractor: KeyguardWakeDirectlyToGoneInteractor, + private val communalSettingsInteractor: CommunalSettingsInteractor, + private val communalSceneInteractor: CommunalSceneInteractor, + private val communalInteractor: CommunalInteractor, ) : TransitionInteractor( fromState = KeyguardState.AOD, @@ -103,6 +110,7 @@ constructor( val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value val biometricUnlockMode = keyguardInteractor.biometricUnlockState.value.mode val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value + val shouldShowCommunal = communalInteractor.shouldShowCommunal.value if (!maybeHandleInsecurePowerGesture()) { val shouldTransitionToLockscreen = @@ -129,6 +137,9 @@ constructor( (!KeyguardWmStateRefactor.isEnabled && canDismissLockscreen()) || (KeyguardWmStateRefactor.isEnabled && canWakeDirectlyToGone) + val shouldTransitionToCommunal = + communalSettingsInteractor.isV2FlagEnabled() && shouldShowCommunal + if (shouldTransitionToGone) { // TODO(b/360368320): Adapt for scene framework if (SceneContainerFlag.isEnabled) return@collect @@ -137,6 +148,11 @@ constructor( modeOnCanceled = TransitionModeOnCanceled.REVERSE, ownerReason = "canWakeDirectlyToGone = true", ) + } else if (shouldTransitionToCommunal) { + communalSceneInteractor.changeScene( + CommunalScenes.Communal, + "listen for aod to communal", + ) } else if (shouldTransitionToLockscreen) { val modeOnCanceled = if (startedStep.from == KeyguardState.LOCKSCREEN) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index 6f5f662d6fa3..0700ec639153 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -159,6 +159,7 @@ constructor( val isKeyguardOccludedLegacy = keyguardInteractor.isKeyguardOccluded.value val primaryBouncerShowing = keyguardInteractor.primaryBouncerShowing.value val isKeyguardGoingAway = keyguardInteractor.isKeyguardGoingAway.value + val canStartDreaming = dreamManager.canStartDreaming(false) if (!deviceEntryInteractor.isLockscreenEnabled()) { if (!SceneContainerFlag.isEnabled) { @@ -191,6 +192,13 @@ constructor( if (!SceneContainerFlag.isEnabled) { transitionToGlanceableHub() } + } else if (canStartDreaming) { + // If we're waking up to dream, transition directly to dreaming without + // showing the lockscreen. + startTransitionTo( + KeyguardState.DREAMING, + ownerReason = "moving from doze to dream", + ) } else { startTransitionTo(KeyguardState.LOCKSCREEN) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt index 2eeba0f10e0c..3ad862b761fc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt @@ -77,7 +77,7 @@ constructor( if (!communalSettingsInteractor.isCommunalFlagEnabled()) { return } - listenForHubToDozing() + listenForHubToAodOrDozing() listenForHubToPrimaryBouncer() listenForHubToAlternateBouncer() listenForHubToOccluded() @@ -123,15 +123,15 @@ constructor( } } - private fun listenForHubToDozing() { + private fun listenForHubToAodOrDozing() { scope.launch { powerInteractor.isAsleep .filterRelevantKeyguardStateAnd { isAsleep -> isAsleep } .collect { - communalSceneInteractor.snapToScene( + communalSceneInteractor.changeScene( newScene = CommunalScenes.Blank, - loggingReason = "hub to dozing", - keyguardState = KeyguardState.DOZING, + loggingReason = "hub to sleep", + keyguardState = keyguardInteractor.asleepKeyguardState.value, ) } } @@ -254,5 +254,6 @@ constructor( val TO_LOCKSCREEN_DURATION = 1.seconds val TO_BOUNCER_DURATION = 400.milliseconds val TO_OCCLUDED_DURATION = 450.milliseconds + val TO_AOD_DURATION = 500.milliseconds } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt index 5f821022d580..1b70ff84f09d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt @@ -119,7 +119,8 @@ constructor( } else { val targetState = if (idle.currentScene == Scenes.Lockscreen) { - transitionInteractor.startedKeyguardTransitionStep.value.from + repository.nextLockscreenTargetState.value + ?: transitionInteractor.startedKeyguardTransitionStep.value.from } else { UNDEFINED } @@ -197,11 +198,11 @@ constructor( TransitionInfo( ownerName = this::class.java.simpleName, from = UNDEFINED, - to = repository.nextLockscreenTargetState.value, + to = repository.nextLockscreenTargetState.value ?: DEFAULT_STATE, animator = null, modeOnCanceled = TransitionModeOnCanceled.RESET, ) - repository.nextLockscreenTargetState.value = DEFAULT_STATE + repository.nextLockscreenTargetState.value = null startTransition(newTransition) } @@ -215,7 +216,7 @@ constructor( animator = null, modeOnCanceled = TransitionModeOnCanceled.RESET, ) - repository.nextLockscreenTargetState.value = DEFAULT_STATE + repository.nextLockscreenTargetState.value = null startTransition(newTransition) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index 8e385385b8c4..c7791cda7046 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt @@ -26,6 +26,8 @@ import android.view.HapticFeedbackConstants import android.view.InputDevice import android.view.MotionEvent import android.view.View +import android.view.View.GONE +import android.view.View.INVISIBLE import android.view.View.OnLayoutChangeListener import android.view.View.VISIBLE import android.view.ViewGroup @@ -304,8 +306,9 @@ object KeyguardRootViewBinder { if (isVisible.value) { blueprintViewModel.refreshBlueprint() } - childViews[aodPromotedNotificationId] - ?.setAodNotifIconContainerIsVisible(isVisible) + childViews[aodPromotedNotificationId]?.setAodPromotedNotifIsVisible( + isVisible + ) } } @@ -313,7 +316,7 @@ object KeyguardRootViewBinder { shadeInteractor.isAnyFullyExpanded.collect { isFullyAnyExpanded -> view.visibility = if (isFullyAnyExpanded) { - View.INVISIBLE + INVISIBLE } else { View.VISIBLE } @@ -370,6 +373,14 @@ object KeyguardRootViewBinder { repeatOnLifecycle(Lifecycle.State.STARTED) { if (wallpaperFocalAreaViewModel.hasFocalArea.value) { launch { + wallpaperFocalAreaViewModel.wallpaperFocalAreaBounds.collect { + wallpaperFocalAreaBounds -> + wallpaperFocalAreaViewModel.setFocalAreaBounds( + wallpaperFocalAreaBounds + ) + } + } + launch { wallpaperFocalAreaViewModel.wallpaperFocalAreaBounds .filterNotNull() .collect { wallpaperFocalAreaViewModel.setFocalAreaBounds(it) } @@ -516,10 +527,10 @@ object KeyguardRootViewBinder { visibility = if (isVisible.value) { alpha = 1f - View.VISIBLE + VISIBLE } else { alpha = 0f - View.INVISIBLE + INVISIBLE } } @@ -533,6 +544,36 @@ object KeyguardRootViewBinder { } } + private fun View.setAodPromotedNotifIsVisible(isVisible: AnimatedValue<Boolean>) { + animate().cancel() + val animatorListener = + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + isVisible.stopAnimating() + } + } + + if (isVisible.isAnimating) { + if (isVisible.value) { + alpha = 0f + visibility = VISIBLE + CrossFadeHelper.fadeIn(this, animatorListener) + } else { + CrossFadeHelper.fadeOut(this, animatorListener) + } + } else { + if (isVisible.value) { + alpha = 1f + visibility = VISIBLE + } else { + // Hide with GONE, not INVISIBLE, so there won't be a redundant bottom + // margin between the smart space and the shelf. + alpha = 0f + visibility = GONE + } + } + } + private fun MotionEvent.isTouchscreenSource(): Boolean { return device?.supportsSource(InputDevice.SOURCE_TOUCHSCREEN) == true } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt index dba2578f79da..c4a7e1ed95e1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt @@ -21,6 +21,7 @@ import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransiti import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.AodToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToOccludedTransitionViewModel @@ -33,6 +34,7 @@ import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransiti import com.android.systemui.keyguard.ui.viewmodel.DreamingToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel @@ -118,6 +120,12 @@ abstract class DeviceEntryIconTransitionModule { @Binds @IntoSet + abstract fun aodToGlanceableHub( + impl: AodToGlanceableHubTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun dozingToGone(impl: DozingToGoneTransitionViewModel): DeviceEntryIconTransition @Binds @@ -258,6 +266,12 @@ abstract class DeviceEntryIconTransitionModule { @Binds @IntoSet + abstract fun glanceableHubToAod( + impl: GlanceableHubToAodTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun occludedToGlanceableHub( impl: OccludedToGlanceableHubTransitionViewModel ): DeviceEntryIconTransition diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModel.kt new file mode 100644 index 000000000000..45f8f10595e4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModel.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import android.util.MathUtils +import com.android.systemui.Flags.lightRevealMigration +import com.android.systemui.communal.ui.compose.TransitionDuration +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.dagger.GlanceableHubBlurComponent +import com.android.systemui.keyguard.shared.model.Edge +import com.android.systemui.keyguard.shared.model.KeyguardState.AOD +import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.keyguard.ui.transitions.GlanceableHubTransition +import com.android.systemui.scene.shared.model.Scenes +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.flow.Flow + +@SysUISingleton +class AodToGlanceableHubTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, + blurFactory: GlanceableHubBlurComponent.Factory, +) : DeviceEntryIconTransition, GlanceableHubTransition { + private val transitionAnimation = + animationFlow + .setup( + duration = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS.milliseconds, + edge = Edge.create(AOD, Scenes.Communal), + ) + .setupWithoutSceneContainer(edge = Edge.create(AOD, GLANCEABLE_HUB)) + + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(1f) + + /** Fade out the lockscreen during a transition to GLANCEABLE_HUB. */ + fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> { + var currentAlpha = 0f + return transitionAnimation.sharedFlow( + duration = 250.milliseconds, + startTime = + if (lightRevealMigration()) { + 100.milliseconds // Wait for the light reveal to "hit" the LS elements. + } else { + 0.milliseconds + }, + onStart = { + currentAlpha = + if (lightRevealMigration()) { + viewState.alpha() + } else { + 0f + } + }, + onStep = { MathUtils.lerp(currentAlpha, 0f, it) }, + ) + } + + override val windowBlurRadius: Flow<Float> = + blurFactory.create(transitionAnimation).getBlurProvider().enterBlurRadius +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt index 75bba489f893..0ccb24a9858a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt @@ -60,6 +60,7 @@ constructor( primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel, primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel, lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel, + glanceableHubToAodTransitionViewModel: GlanceableHubToAodTransitionViewModel, ) { val color: Flow<Int> = deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground -> @@ -106,6 +107,7 @@ constructor( primaryBouncerToLockscreenTransitionViewModel .deviceEntryBackgroundViewAlpha, lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha, + glanceableHubToAodTransitionViewModel.deviceEntryBackgroundViewAlpha, ) .merge() .onStart { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt index e6a85c6860c5..9018c58a7e36 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToDreamingTransitionViewModel.kt @@ -39,4 +39,6 @@ constructor(animationFlow: KeyguardTransitionAnimationFlow) { ) val lockscreenAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(0f) + // Notifications should not be shown while transitioning to dream. + val notificationAlpha = transitionAnimation.immediatelyTransitionTo(0f) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModel.kt new file mode 100644 index 000000000000..6a45845a02c6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModel.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.FromGlanceableHubTransitionInteractor +import com.android.systemui.keyguard.shared.model.Edge +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.KeyguardState.AOD +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import com.android.systemui.scene.shared.model.Scenes +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flatMapLatest + +@OptIn(ExperimentalCoroutinesApi::class) +@SysUISingleton +class GlanceableHubToAodTransitionViewModel +@Inject +constructor( + deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + + private val transitionAnimation = + animationFlow + .setup( + duration = FromGlanceableHubTransitionInteractor.TO_AOD_DURATION, + edge = Edge.create(from = Scenes.Communal, to = AOD), + ) + .setupWithoutSceneContainer(edge = Edge.create(KeyguardState.GLANCEABLE_HUB, AOD)) + + val deviceEntryBackgroundViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) + + /** Lockscreen views alpha */ + val lockscreenAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + startTime = 233.milliseconds, + duration = 250.milliseconds, + onStep = { it }, + ) + + override val deviceEntryParentViewAlpha: Flow<Float> = + deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled + -> + if (udfpsEnrolledAndEnabled) { + transitionAnimation.immediatelyTransitionTo(1f) + } else { + emptyFlow() + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 8e21745e1a31..def87a8e2717 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -100,6 +100,7 @@ constructor( private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel, private val aodToOccludedTransitionViewModel: AodToOccludedTransitionViewModel, private val aodToPrimaryBouncerTransitionViewModel: AodToPrimaryBouncerTransitionViewModel, + private val aodToGlanceableHubTransitionViewModel: AodToGlanceableHubTransitionViewModel, private val dozingToDreamingTransitionViewModel: DozingToDreamingTransitionViewModel, private val dozingToGoneTransitionViewModel: DozingToGoneTransitionViewModel, private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel, @@ -111,6 +112,7 @@ constructor( private val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel, private val glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel, + private val glanceableHubToAodTransitionViewModel: GlanceableHubToAodTransitionViewModel, private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel, private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel, private val goneToDreamingTransitionViewModel: GoneToDreamingTransitionViewModel, @@ -258,6 +260,7 @@ constructor( aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState), aodToOccludedTransitionViewModel.lockscreenAlpha(viewState), aodToPrimaryBouncerTransitionViewModel.lockscreenAlpha, + aodToGlanceableHubTransitionViewModel.lockscreenAlpha(viewState), dozingToDreamingTransitionViewModel.lockscreenAlpha, dozingToGoneTransitionViewModel.lockscreenAlpha(viewState), dozingToLockscreenTransitionViewModel.lockscreenAlpha, @@ -267,6 +270,7 @@ constructor( dreamingToGoneTransitionViewModel.lockscreenAlpha, dreamingToLockscreenTransitionViewModel.lockscreenAlpha, glanceableHubToLockscreenTransitionViewModel.keyguardAlpha, + glanceableHubToAodTransitionViewModel.lockscreenAlpha, goneToAodTransitionViewModel.enterFromTopAnimationAlpha, goneToDozingTransitionViewModel.lockscreenAlpha, goneToDreamingTransitionViewModel.lockscreenAlpha, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt index 21407f3bd6d4..9badf8503c75 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/ColorSchemeTransition.kt @@ -27,6 +27,7 @@ import android.graphics.drawable.RippleDrawable import com.android.internal.R import com.android.internal.annotations.VisibleForTesting import com.android.settingslib.Utils +import com.android.systemui.Flags import com.android.systemui.media.controls.ui.view.MediaViewHolder import com.android.systemui.monet.ColorScheme import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffect @@ -51,7 +52,7 @@ interface ColorTransition { open class AnimatingColorTransition( private val defaultColor: Int, private val extractColor: (ColorScheme) -> Int, - private val applyColor: (Int) -> Unit + private val applyColor: (Int) -> Unit, ) : AnimatorUpdateListener, ColorTransition { private val argbEvaluator = ArgbEvaluator() @@ -105,24 +106,60 @@ internal constructor( private val mediaViewHolder: MediaViewHolder, private val multiRippleController: MultiRippleController, private val turbulenceNoiseController: TurbulenceNoiseController, - animatingColorTransitionFactory: AnimatingColorTransitionFactory + animatingColorTransitionFactory: AnimatingColorTransitionFactory, ) { constructor( context: Context, mediaViewHolder: MediaViewHolder, multiRippleController: MultiRippleController, - turbulenceNoiseController: TurbulenceNoiseController + turbulenceNoiseController: TurbulenceNoiseController, ) : this( context, mediaViewHolder, multiRippleController, turbulenceNoiseController, - ::AnimatingColorTransition + ::AnimatingColorTransition, ) + var loadingEffect: LoadingEffect? = null - val bgColor = context.getColor(com.google.android.material.R.color.material_dynamic_neutral20) - val surfaceColor = + // Defaults may be briefly visible before loading a new player's colors + private val backgroundDefault = context.getColor(R.color.system_on_surface_light) + private val primaryDefault = context.getColor(R.color.system_primary_dark) + private val onPrimaryDefault = context.getColor(R.color.system_on_primary_dark) + + private val backgroundColor: AnimatingColorTransition by lazy { + animatingColorTransitionFactory(backgroundDefault, ::backgroundFromScheme) { color -> + mediaViewHolder.albumView.backgroundTintList = ColorStateList.valueOf(color) + } + } + + private val primaryColor: AnimatingColorTransition by lazy { + animatingColorTransitionFactory(primaryDefault, ::primaryFromScheme) { primaryColor -> + val primaryColorList = ColorStateList.valueOf(primaryColor) + mediaViewHolder.actionPlayPause.backgroundTintList = primaryColorList + mediaViewHolder.seamlessButton.backgroundTintList = primaryColorList + (mediaViewHolder.seamlessButton.background as? RippleDrawable)?.let { + it.setColor(primaryColorList) + it.effectColor = primaryColorList + } + mediaViewHolder.seekBar.progressBackgroundTintList = primaryColorList + } + } + + private val onPrimaryColor: AnimatingColorTransition by lazy { + animatingColorTransitionFactory(onPrimaryDefault, ::onPrimaryFromScheme) { onPrimaryColor -> + val onPrimaryColorList = ColorStateList.valueOf(onPrimaryColor) + mediaViewHolder.actionPlayPause.imageTintList = onPrimaryColorList + mediaViewHolder.seamlessText.setTextColor(onPrimaryColor) + mediaViewHolder.seamlessIcon.imageTintList = onPrimaryColorList + } + } + + // TODO(media_controls_a11y_colors): remove the below color definitions + private val bgColor = + context.getColor(com.google.android.material.R.color.material_dynamic_neutral20) + private val surfaceColor: AnimatingColorTransition by lazy { animatingColorTransitionFactory(bgColor, ::surfaceFromScheme) { surfaceColor -> val colorList = ColorStateList.valueOf(surfaceColor) mediaViewHolder.seamlessIcon.imageTintList = colorList @@ -130,10 +167,12 @@ internal constructor( mediaViewHolder.albumView.backgroundTintList = colorList mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor) } - val accentPrimary = + } + + private val accentPrimary: AnimatingColorTransition by lazy { animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorPrimary), - ::accentPrimaryFromScheme + ::accentPrimaryFromScheme, ) { accentPrimary -> val accentColorList = ColorStateList.valueOf(accentPrimary) mediaViewHolder.actionPlayPause.backgroundTintList = accentColorList @@ -142,11 +181,12 @@ internal constructor( turbulenceNoiseController.updateNoiseColor(accentPrimary) loadingEffect?.updateColor(accentPrimary) } + } - val accentSecondary = + private val accentSecondary: AnimatingColorTransition by lazy { animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorPrimary), - ::accentSecondaryFromScheme + ::accentSecondaryFromScheme, ) { accentSecondary -> val colorList = ColorStateList.valueOf(accentSecondary) (mediaViewHolder.seamlessButton.background as? RippleDrawable)?.let { @@ -154,8 +194,9 @@ internal constructor( it.effectColor = colorList } } + } - val colorSeamless = + private val colorSeamless: AnimatingColorTransition by lazy { animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorPrimary), { colorScheme: ColorScheme -> @@ -170,13 +211,14 @@ internal constructor( { seamlessColor: Int -> val accentColorList = ColorStateList.valueOf(seamlessColor) mediaViewHolder.seamlessButton.backgroundTintList = accentColorList - } + }, ) + } - val textPrimary = + private val textPrimary: AnimatingColorTransition by lazy { animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorPrimary), - ::textPrimaryFromScheme + ::textPrimaryFromScheme, ) { textPrimary -> mediaViewHolder.titleText.setTextColor(textPrimary) val textColorList = ColorStateList.valueOf(textPrimary) @@ -189,44 +231,81 @@ internal constructor( } mediaViewHolder.gutsViewHolder.setTextPrimaryColor(textPrimary) } + } - val textPrimaryInverse = + private val textPrimaryInverse: AnimatingColorTransition by lazy { animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorPrimaryInverse), - ::textPrimaryInverseFromScheme + ::textPrimaryInverseFromScheme, ) { textPrimaryInverse -> mediaViewHolder.actionPlayPause.imageTintList = ColorStateList.valueOf(textPrimaryInverse) } + } - val textSecondary = + private val textSecondary: AnimatingColorTransition by lazy { animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorSecondary), - ::textSecondaryFromScheme + ::textSecondaryFromScheme, ) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) } + } - val textTertiary = + private val textTertiary: AnimatingColorTransition by lazy { animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorTertiary), - ::textTertiaryFromScheme + ::textTertiaryFromScheme, ) { textTertiary -> mediaViewHolder.seekBar.progressBackgroundTintList = ColorStateList.valueOf(textTertiary) } + } - val colorTransitions = - arrayOf( - surfaceColor, - colorSeamless, - accentPrimary, - accentSecondary, - textPrimary, - textPrimaryInverse, - textSecondary, - textTertiary, - ) + fun getDeviceIconColor(): Int { + if (Flags.mediaControlsA11yColors()) { + return onPrimaryColor.targetColor + } + return surfaceColor.targetColor + } + + fun getAppIconColor(): Int { + if (Flags.mediaControlsA11yColors()) { + return primaryColor.targetColor + } + return accentPrimary.targetColor + } + + fun getSurfaceEffectColor(): Int { + if (Flags.mediaControlsA11yColors()) { + return primaryColor.targetColor + } + return accentPrimary.targetColor + } + + fun getGutsTextColor(): Int { + if (Flags.mediaControlsA11yColors()) { + return context.getColor(com.android.systemui.res.R.color.media_on_background) + } + return textPrimary.targetColor + } + + private fun getColorTransitions(): Array<AnimatingColorTransition> { + return if (Flags.mediaControlsA11yColors()) { + arrayOf(backgroundColor, primaryColor, onPrimaryColor) + } else { + arrayOf( + surfaceColor, + colorSeamless, + accentPrimary, + accentSecondary, + textPrimary, + textPrimaryInverse, + textSecondary, + textTertiary, + ) + } + } private fun loadDefaultColor(id: Int): Int { return Utils.getColorAttr(context, id).defaultColor @@ -234,15 +313,26 @@ internal constructor( fun updateColorScheme(colorScheme: ColorScheme?): Boolean { var anyChanged = false - colorTransitions.forEach { + getColorTransitions().forEach { val isChanged = it.updateColorScheme(colorScheme) // Ignore changes to colorSeamless, since that is expected when toggling dark mode + // TODO(media_controls_a11y_colors): remove, not necessary if (it == colorSeamless) return@forEach anyChanged = isChanged || anyChanged } - colorScheme?.let { mediaViewHolder.gutsViewHolder.colorScheme = colorScheme } + if (Flags.mediaControlsA11yColors()) { + getSurfaceEffectColor().let { + multiRippleController.updateColor(it) + turbulenceNoiseController.updateNoiseColor(it) + loadingEffect?.updateColor(it) + } + mediaViewHolder.gutsViewHolder.setTextColor(getGutsTextColor()) + colorScheme?.let { mediaViewHolder.gutsViewHolder.setColors(it) } + } else { + colorScheme?.let { mediaViewHolder.gutsViewHolder.colorScheme = colorScheme } + } return anyChanged } } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/MediaColorSchemes.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/MediaColorSchemes.kt index 3c57c83ff9fe..67113a4fe6e7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/MediaColorSchemes.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/animation/MediaColorSchemes.kt @@ -19,28 +19,43 @@ package com.android.systemui.media.controls.ui.animation import com.android.systemui.monet.ColorScheme /** Returns the surface color for media controls based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun surfaceFromScheme(scheme: ColorScheme) = scheme.accent2.s800 // A2-800 /** Returns the primary accent color for media controls based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun accentPrimaryFromScheme(scheme: ColorScheme) = scheme.accent1.s100 // A1-100 /** Returns the secondary accent color for media controls based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun accentSecondaryFromScheme(scheme: ColorScheme) = scheme.accent1.s200 // A1-200 /** Returns the primary text color for media controls based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun textPrimaryFromScheme(scheme: ColorScheme) = scheme.neutral1.s50 // N1-50 /** Returns the inverse of the primary text color for media controls based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun textPrimaryInverseFromScheme(scheme: ColorScheme) = scheme.neutral1.s900 // N1-900 /** Returns the secondary text color for media controls based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun textSecondaryFromScheme(scheme: ColorScheme) = scheme.neutral2.s200 // N2-200 /** Returns the tertiary text color for media controls based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun textTertiaryFromScheme(scheme: ColorScheme) = scheme.neutral2.s400 // N2-400 /** Returns the color for the start of the background gradient based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun backgroundStartFromScheme(scheme: ColorScheme) = scheme.accent2.s700 // A2-700 /** Returns the color for the end of the background gradient based on the scheme. */ +@Deprecated("Remove with media_controls_a11y_colors") internal fun backgroundEndFromScheme(scheme: ColorScheme) = scheme.accent1.s700 // A1-700 + +internal fun backgroundFromScheme(scheme: ColorScheme) = scheme.materialScheme.getOnSurface() + +internal fun primaryFromScheme(scheme: ColorScheme) = scheme.materialScheme.getPrimaryFixed() + +internal fun onPrimaryFromScheme(scheme: ColorScheme) = scheme.materialScheme.getOnPrimaryFixed() diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt index 910d3a84aeae..3f538203aee9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt @@ -36,6 +36,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.app.tracing.coroutines.launchTraced as launch import com.android.settingslib.widget.AdaptiveIcon +import com.android.systemui.Flags import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.qualifiers.Background @@ -49,7 +50,9 @@ import com.android.systemui.media.controls.ui.view.MediaViewHolder import com.android.systemui.media.controls.ui.viewmodel.MediaActionViewModel import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Companion.MEDIA_PLAYER_SCRIM_END_ALPHA +import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Companion.MEDIA_PLAYER_SCRIM_END_ALPHA_LEGACY import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Companion.MEDIA_PLAYER_SCRIM_START_ALPHA +import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Companion.MEDIA_PLAYER_SCRIM_START_ALPHA_LEGACY import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Companion.SEMANTIC_ACTIONS_ALL import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Companion.SEMANTIC_ACTIONS_COMPACT import com.android.systemui.media.controls.ui.viewmodel.MediaOutputSwitcherViewModel @@ -198,7 +201,9 @@ object MediaControlViewBinder { is Icon.Loaded -> { val icon = viewModel.deviceIcon.drawable if (icon is AdaptiveIcon) { - icon.setBackgroundColor(viewController.colorSchemeTransition.bgColor) + icon.setBackgroundColor( + viewController.colorSchemeTransition.getDeviceIconColor() + ) } viewHolder.seamlessIcon.setImageDrawable(icon) } @@ -431,11 +436,16 @@ object MediaControlViewBinder { TAG, ) val isArtworkBound = wallpaperColors != null + val darkTheme = !Flags.mediaControlsA11yColors() val scheme = - wallpaperColors?.let { ColorScheme(it, true, Style.CONTENT) } + wallpaperColors?.let { ColorScheme(it, darkTheme, Style.CONTENT) } ?: let { if (viewModel.launcherIcon is Icon.Loaded) { - MediaArtworkHelper.getColorScheme(viewModel.launcherIcon.drawable, TAG) + MediaArtworkHelper.getColorScheme( + viewModel.launcherIcon.drawable, + TAG, + darkTheme, + ) } else { null } @@ -496,7 +506,7 @@ object MediaControlViewBinder { } } else { viewHolder.appIcon.setColorFilter( - viewController.colorSchemeTransition.accentPrimary.targetColor + viewController.colorSchemeTransition.getAppIconColor() ) viewHolder.appIcon.setImageIcon(viewModel.appIcon) } @@ -528,12 +538,24 @@ object MediaControlViewBinder { height: Int, ): LayerDrawable { val albumArt = MediaArtworkHelper.getScaledBackground(context, artworkIcon, width, height) + val startAlpha = + if (Flags.mediaControlsA11yColors()) { + MEDIA_PLAYER_SCRIM_START_ALPHA + } else { + MEDIA_PLAYER_SCRIM_START_ALPHA_LEGACY + } + val endAlpha = + if (Flags.mediaControlsA11yColors()) { + MEDIA_PLAYER_SCRIM_END_ALPHA + } else { + MEDIA_PLAYER_SCRIM_END_ALPHA_LEGACY + } return MediaArtworkHelper.setUpGradientColorOnDrawable( albumArt, context.getDrawable(R.drawable.qs_media_scrim)?.mutate() as GradientDrawable, mutableColorScheme, - MEDIA_PLAYER_SCRIM_START_ALPHA, - MEDIA_PLAYER_SCRIM_END_ALPHA, + startAlpha, + endAlpha, ) } @@ -572,7 +594,7 @@ object MediaControlViewBinder { maxSize, maxSize, button.context.resources.displayMetrics.density, - colorSchemeTransition.accentPrimary.currentColor, + colorSchemeTransition.getSurfaceEffectColor(), opacity = 100, sparkleStrength = 0f, baseRingFadeParams = null, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/SeekBarObserver.kt index 34f7c4dcaec0..c9716be52408 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/SeekBarObserver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/SeekBarObserver.kt @@ -18,6 +18,9 @@ package com.android.systemui.media.controls.ui.binder import android.animation.Animator import android.animation.ObjectAnimator +import android.icu.text.MeasureFormat +import android.icu.util.Measure +import android.icu.util.MeasureUnit import android.text.format.DateUtils import androidx.annotation.UiThread import androidx.lifecycle.Observer @@ -28,8 +31,11 @@ import com.android.systemui.media.controls.ui.drawable.SquigglyProgress import com.android.systemui.media.controls.ui.view.MediaViewHolder import com.android.systemui.media.controls.ui.viewmodel.SeekBarViewModel import com.android.systemui.res.R +import java.util.Locale private const val TAG = "SeekBarObserver" +private const val MIN_IN_SEC = 60 +private const val HOUR_IN_SEC = MIN_IN_SEC * 60 /** * Observer for changes from SeekBarViewModel. @@ -127,10 +133,9 @@ open class SeekBarObserver(private val holder: MediaViewHolder) : } holder.seekBar.setMax(data.duration) - val totalTimeString = - DateUtils.formatElapsedTime(data.duration / DateUtils.SECOND_IN_MILLIS) + val totalTimeDescription = formatTimeContentDescription(data.duration) if (data.scrubbing) { - holder.scrubbingTotalTimeView.text = totalTimeString + holder.scrubbingTotalTimeView.text = formatTimeLabel(data.duration) } data.elapsedTime?.let { @@ -148,20 +153,62 @@ open class SeekBarObserver(private val holder: MediaViewHolder) : } } - val elapsedTimeString = DateUtils.formatElapsedTime(it / DateUtils.SECOND_IN_MILLIS) + val elapsedTimeDescription = formatTimeContentDescription(it) if (data.scrubbing) { - holder.scrubbingElapsedTimeView.text = elapsedTimeString + holder.scrubbingElapsedTimeView.text = formatTimeLabel(it) } holder.seekBar.contentDescription = holder.seekBar.context.getString( R.string.controls_media_seekbar_description, - elapsedTimeString, - totalTimeString + elapsedTimeDescription, + totalTimeDescription, ) } } + /** Returns a time string suitable for display, e.g. "12:34" */ + private fun formatTimeLabel(milliseconds: Int): CharSequence { + return DateUtils.formatElapsedTime(milliseconds / DateUtils.SECOND_IN_MILLIS) + } + + /** + * Returns a time string suitable for content description, e.g. "12 minutes 34 seconds" + * + * Follows same logic as Chronometer#formatDuration + */ + private fun formatTimeContentDescription(milliseconds: Int): CharSequence { + var seconds = milliseconds / DateUtils.SECOND_IN_MILLIS + + val hours = + if (seconds >= HOUR_IN_SEC) { + seconds / HOUR_IN_SEC + } else { + 0 + } + seconds -= hours * HOUR_IN_SEC + + val minutes = + if (seconds >= MIN_IN_SEC) { + seconds / MIN_IN_SEC + } else { + 0 + } + seconds -= minutes * MIN_IN_SEC + + val measures = arrayListOf<Measure>() + if (hours > 0) { + measures.add(Measure(hours, MeasureUnit.HOUR)) + } + if (minutes > 0) { + measures.add(Measure(minutes, MeasureUnit.MINUTE)) + } + measures.add(Measure(seconds, MeasureUnit.SECOND)) + + return MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) + .formatMeasures(*measures.toTypedArray()) + } + @VisibleForTesting open fun buildResetAnimator(targetTime: Int): Animator { val animator = @@ -169,7 +216,7 @@ open class SeekBarObserver(private val holder: MediaViewHolder) : holder.seekBar, "progress", holder.seekBar.progress, - targetTime + RESET_ANIMATION_DURATION_MS + targetTime + RESET_ANIMATION_DURATION_MS, ) animator.setAutoCancel(true) animator.duration = RESET_ANIMATION_DURATION_MS.toLong() diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt index 606f71a162d8..d26a723035c0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt @@ -55,7 +55,7 @@ constructor( private val bypassController: KeyguardBypassController, private val statusBarStateController: SysuiStatusBarStateController, @ShadeDisplayAware private val context: Context, - configurationController: ConfigurationController, + @ShadeDisplayAware configurationController: ConfigurationController, private val splitShadeStateController: SplitShadeStateController, private val logger: KeyguardMediaControllerLogger, dumpManager: DumpManager, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt index 93c4bafe4273..55d8b8c4def0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt @@ -132,7 +132,7 @@ class MediaCarouselController @Inject constructor( @Application applicationScope: CoroutineScope, - private val context: Context, + @Main private val context: Context, private val mediaControlPanelFactory: Provider<MediaControlPanel>, private val visualStabilityProvider: VisualStabilityProvider, private val mediaHostStatesManager: MediaHostStatesManager, @@ -143,7 +143,7 @@ constructor( @Background private val bgExecutor: Executor, @Background private val backgroundDispatcher: CoroutineDispatcher, private val mediaManager: MediaDataManager, - configurationController: ConfigurationController, + @Main configurationController: ConfigurationController, private val falsingManager: FalsingManager, dumpManager: DumpManager, private val logger: MediaUiEventLogger, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java index 2bf6a10c5258..694a4c7e493d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java @@ -23,6 +23,10 @@ import static com.android.systemui.Flags.communalHub; import static com.android.systemui.Flags.mediaLockscreenLaunchAnimation; import static com.android.systemui.media.controls.domain.pipeline.MediaActionsKt.getNotificationActions; import static com.android.systemui.media.controls.shared.model.SmartspaceMediaDataKt.NUM_REQUIRED_RECOMMENDATIONS; +import static com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.MEDIA_PLAYER_SCRIM_END_ALPHA; +import static com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.MEDIA_PLAYER_SCRIM_END_ALPHA_LEGACY; +import static com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.MEDIA_PLAYER_SCRIM_START_ALPHA; +import static com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.MEDIA_PLAYER_SCRIM_START_ALPHA_LEGACY; import android.animation.Animator; import android.animation.AnimatorInflater; @@ -175,9 +179,7 @@ public class MediaControlPanel { protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761; private static final float REC_MEDIA_COVER_SCALE_FACTOR = 1.25f; - private static final float MEDIA_SCRIM_START_ALPHA = 0.25f; private static final float MEDIA_REC_SCRIM_START_ALPHA = 0.15f; - private static final float MEDIA_PLAYER_SCRIM_END_ALPHA = 1.0f; private static final float MEDIA_REC_SCRIM_END_ALPHA = 1.0f; private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS); @@ -305,7 +307,7 @@ public class MediaControlPanel { */ @Inject public MediaControlPanel( - Context context, + @Main Context context, @Background Executor backgroundExecutor, @Main DelayableExecutor mainExecutor, ActivityStarter activityStarter, @@ -730,7 +732,7 @@ public class MediaControlPanel { Drawable icon = device.getIcon(); if (icon instanceof AdaptiveIcon) { AdaptiveIcon aIcon = (AdaptiveIcon) icon; - aIcon.setBackgroundColor(mColorSchemeTransition.getBgColor()); + aIcon.setBackgroundColor(mColorSchemeTransition.getDeviceIconColor()); iconView.setImageDrawable(aIcon); } else { iconView.setImageDrawable(icon); @@ -921,8 +923,9 @@ public class MediaControlPanel { boolean isArtworkBound; Icon artworkIcon = data.getArtwork(); WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon); + boolean darkTheme = !Flags.mediaControlsA11yColors(); if (wallpaperColors != null) { - mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT); + mutableColorScheme = new ColorScheme(wallpaperColors, darkTheme, Style.CONTENT); artwork = addGradientToPlayerAlbum(artworkIcon, mutableColorScheme, finalWidth, finalHeight); isArtworkBound = true; @@ -933,8 +936,8 @@ public class MediaControlPanel { try { Drawable icon = mContext.getPackageManager() .getApplicationIcon(data.getPackageName()); - mutableColorScheme = new ColorScheme(WallpaperColors.fromDrawable(icon), true, - Style.CONTENT); + mutableColorScheme = new ColorScheme(WallpaperColors.fromDrawable(icon), + darkTheme, Style.CONTENT); } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e); } @@ -950,7 +953,8 @@ public class MediaControlPanel { mArtworkBoundId = reqId; // Transition Colors to current color scheme - boolean colorSchemeChanged = mColorSchemeTransition.updateColorScheme(colorScheme); + boolean colorSchemeChanged; + colorSchemeChanged = mColorSchemeTransition.updateColorScheme(colorScheme); // Bind the album view to the artwork or a transition drawable ImageView albumView = mMediaViewHolder.getAlbumView(); @@ -973,7 +977,6 @@ public class MediaControlPanel { transitionDrawable.setLayerGravity(0, Gravity.CENTER); transitionDrawable.setLayerGravity(1, Gravity.CENTER); transitionDrawable.setCrossFadeEnabled(true); - albumView.setImageDrawable(transitionDrawable); transitionDrawable.startTransition(isArtworkBound ? 333 : 80); } @@ -986,8 +989,7 @@ public class MediaControlPanel { appIconView.clearColorFilter(); if (data.getAppIcon() != null && !data.getResumption()) { appIconView.setImageIcon(data.getAppIcon()); - appIconView.setColorFilter( - mColorSchemeTransition.getAccentPrimary().getTargetColor()); + appIconView.setColorFilter(mColorSchemeTransition.getAppIconColor()); } else { // Resume players use launcher icon appIconView.setColorFilter(getGrayscaleFilter()); @@ -1092,8 +1094,12 @@ public class MediaControlPanel { Drawable albumArt = getScaledBackground(artworkIcon, width, height); GradientDrawable gradient = (GradientDrawable) mContext.getDrawable( R.drawable.qs_media_scrim).mutate(); + if (Flags.mediaControlsA11yColors()) { + return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme, + MEDIA_PLAYER_SCRIM_START_ALPHA, MEDIA_PLAYER_SCRIM_END_ALPHA); + } return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme, - MEDIA_SCRIM_START_ALPHA, MEDIA_PLAYER_SCRIM_END_ALPHA); + MEDIA_PLAYER_SCRIM_START_ALPHA_LEGACY, MEDIA_PLAYER_SCRIM_END_ALPHA_LEGACY); } @VisibleForTesting @@ -1113,12 +1119,21 @@ public class MediaControlPanel { private LayerDrawable setupGradientColorOnDrawable(Drawable albumArt, GradientDrawable gradient, ColorScheme mutableColorScheme, float startAlpha, float endAlpha) { + int startColor; + int endColor; + if (Flags.mediaControlsA11yColors()) { + startColor = MediaColorSchemesKt.backgroundFromScheme(mutableColorScheme); + endColor = startColor; + } else { + startColor = MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme); + endColor = MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme); + } gradient.setColors(new int[]{ ColorUtilKt.getColorWithAlpha( - MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme), + startColor, startAlpha), ColorUtilKt.getColorWithAlpha( - MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme), + endColor, endAlpha), }); return new LayerDrawable(new Drawable[]{albumArt, gradient}); @@ -1308,7 +1323,7 @@ public class MediaControlPanel { /* maxWidth= */ maxSize, /* maxHeight= */ maxSize, /* pixelDensity= */ getContext().getResources().getDisplayMetrics().density, - mColorSchemeTransition.getAccentPrimary().getCurrentColor(), + /* color= */ mColorSchemeTransition.getSurfaceEffectColor(), /* opacity= */ 100, /* sparkleStrength= */ 0f, /* baseRingFadeParams= */ null, @@ -1330,10 +1345,13 @@ public class MediaControlPanel { int width = targetView.getWidth(); int height = targetView.getHeight(); Random random = new Random(); + float luminosity = (Flags.mediaControlsA11yColors()) + ? 0.6f + : TurbulenceNoiseAnimationConfig.DEFAULT_LUMINOSITY_MULTIPLIER; return new TurbulenceNoiseAnimationConfig( /* gridCount= */ 2.14f, - TurbulenceNoiseAnimationConfig.DEFAULT_LUMINOSITY_MULTIPLIER, + /* luminosityMultiplier= */ luminosity, /* noiseOffsetX= */ random.nextFloat(), /* noiseOffsetY= */ random.nextFloat(), /* noiseOffsetZ= */ random.nextFloat(), @@ -1341,7 +1359,7 @@ public class MediaControlPanel { /* noiseMoveSpeedY= */ 0f, TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_SPEED_Z, // Color will be correctly updated in ColorSchemeTransition. - /* color= */ mColorSchemeTransition.getAccentPrimary().getCurrentColor(), + /* color= */ mColorSchemeTransition.getSurfaceEffectColor(), /* screenColor= */ Color.BLACK, width, height, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt index 20593942148b..b64cb3dd456a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt @@ -113,7 +113,7 @@ constructor( private val dreamOverlayStateController: DreamOverlayStateController, private val keyguardInteractor: KeyguardInteractor, communalTransitionViewModel: CommunalTransitionViewModel, - configurationController: ConfigurationController, + @ShadeDisplayAware configurationController: ConfigurationController, wakefulnessLifecycle: WakefulnessLifecycle, shadeInteractor: ShadeInteractor, private val secureSettings: SecureSettings, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt index 2b36872dbe36..b687dce20b06 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt @@ -81,8 +81,8 @@ import javax.inject.Inject open class MediaViewController @Inject constructor( - private val context: Context, - private val configurationController: ConfigurationController, + @Main private val context: Context, + @Main private val configurationController: ConfigurationController, private val mediaHostStatesManager: MediaHostStatesManager, private val logger: MediaViewLogger, private val seekBarViewModel: SeekBarViewModel, @@ -1137,6 +1137,7 @@ constructor( ) { gutsViewHolder.gutsText.setTypeface(menuTF) gutsViewHolder.dismissText.setTypeface(menuTF) + gutsViewHolder.cancelText.setTypeface(menuTF) titleText.setTypeface(titleTF) artistText.setTypeface(artistTF) seamlessText.setTypeface(menuTF) @@ -1237,9 +1238,15 @@ constructor( val width = targetView.width val height = targetView.height val random = Random() + val luminosity = + if (Flags.mediaControlsA11yColors()) { + 0.6f + } else { + TurbulenceNoiseAnimationConfig.DEFAULT_LUMINOSITY_MULTIPLIER + } return TurbulenceNoiseAnimationConfig( gridCount = 2.14f, - TurbulenceNoiseAnimationConfig.DEFAULT_LUMINOSITY_MULTIPLIER, + luminosity, random.nextFloat(), random.nextFloat(), random.nextFloat(), @@ -1247,7 +1254,7 @@ constructor( noiseMoveSpeedY = 0f, TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_SPEED_Z, // Color will be correctly updated in ColorSchemeTransition. - colorSchemeTransition.accentPrimary.currentColor, + colorSchemeTransition.getSurfaceEffectColor(), screenColor = Color.BLACK, width.toFloat(), height.toFloat(), diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt index 14a4e2656d7d..557032551308 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaArtworkHelper.kt @@ -25,7 +25,9 @@ import android.graphics.drawable.GradientDrawable import android.graphics.drawable.Icon import android.graphics.drawable.LayerDrawable import android.util.Log +import com.android.systemui.Flags import com.android.systemui.media.controls.ui.animation.backgroundEndFromScheme +import com.android.systemui.media.controls.ui.animation.backgroundFromScheme import com.android.systemui.media.controls.ui.animation.backgroundStartFromScheme import com.android.systemui.monet.ColorScheme import com.android.systemui.monet.Style @@ -89,22 +91,30 @@ object MediaArtworkHelper { startAlpha: Float, endAlpha: Float, ): LayerDrawable { + val startColor = + if (Flags.mediaControlsA11yColors()) { + backgroundFromScheme(colorScheme) + } else { + backgroundStartFromScheme(colorScheme) + } + val endColor = + if (Flags.mediaControlsA11yColors()) { + startColor + } else { + backgroundEndFromScheme(colorScheme) + } gradient.colors = intArrayOf( - getColorWithAlpha(backgroundStartFromScheme(colorScheme), startAlpha), - getColorWithAlpha(backgroundEndFromScheme(colorScheme), endAlpha), + getColorWithAlpha(startColor, startAlpha), + getColorWithAlpha(endColor, endAlpha), ) return LayerDrawable(arrayOf(albumArt, gradient)) } /** Returns [ColorScheme] of media app given its [icon]. */ - fun getColorScheme( - icon: Drawable, - tag: String, - @Style.Type style: Int = Style.TONAL_SPOT, - ): ColorScheme? { + fun getColorScheme(icon: Drawable, tag: String, darkTheme: Boolean): ColorScheme? { return try { - ColorScheme(WallpaperColors.fromDrawable(icon), true, style) + ColorScheme(WallpaperColors.fromDrawable(icon), darkTheme, Style.CONTENT) } catch (e: PackageManager.NameNotFoundException) { Log.w(tag, "Fail to get media app info", e) null diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/GutsViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/GutsViewHolder.kt index a667c5819062..fa500ae53491 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/GutsViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/GutsViewHolder.kt @@ -22,7 +22,10 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageButton import android.widget.TextView +import com.android.systemui.Flags import com.android.systemui.media.controls.ui.animation.accentPrimaryFromScheme +import com.android.systemui.media.controls.ui.animation.onPrimaryFromScheme +import com.android.systemui.media.controls.ui.animation.primaryFromScheme import com.android.systemui.media.controls.ui.animation.surfaceFromScheme import com.android.systemui.media.controls.ui.animation.textPrimaryFromScheme import com.android.systemui.monet.ColorScheme @@ -35,7 +38,7 @@ import com.android.systemui.res.R * Both [MediaViewHolder] and [RecommendationViewHolder] use the same guts menu layout, so this * class helps share logic between the two. */ -class GutsViewHolder constructor(itemView: View) { +class GutsViewHolder(itemView: View) { val gutsText: TextView = itemView.requireViewById(R.id.remove_text) val cancel: View = itemView.requireViewById(R.id.cancel) val cancelText: TextView = itemView.requireViewById(R.id.cancel_text) @@ -44,7 +47,9 @@ class GutsViewHolder constructor(itemView: View) { val settings: ImageButton = itemView.requireViewById(R.id.settings) private var isDismissible: Boolean = true + // TODO(media_controls_a11y_colors): make private var colorScheme: ColorScheme? = null + private var textColorFixed: Int? = null /** Marquees the main text of the guts menu. */ fun marquee(start: Boolean, delay: Long, tag: String) { @@ -67,12 +72,43 @@ class GutsViewHolder constructor(itemView: View) { /** Sets the right colors on all the guts views based on the given [ColorScheme]. */ fun setColors(scheme: ColorScheme) { colorScheme = scheme - setSurfaceColor(surfaceFromScheme(scheme)) - setTextPrimaryColor(textPrimaryFromScheme(scheme)) - setAccentPrimaryColor(accentPrimaryFromScheme(scheme)) + + if (Flags.mediaControlsA11yColors()) { + textColorFixed?.let { setTextColor(it) } + setPrimaryColor(primaryFromScheme(scheme)) + setOnPrimaryColor(onPrimaryFromScheme(scheme)) + } else { + setSurfaceColor(surfaceFromScheme(scheme)) + setTextPrimaryColor(textPrimaryFromScheme(scheme)) + setAccentPrimaryColor(accentPrimaryFromScheme(scheme)) + } + } + + private fun setPrimaryColor(color: Int) { + val colorList = ColorStateList.valueOf(color) + dismissText.backgroundTintList = colorList + cancelText.backgroundTintList = colorList + } + + private fun setOnPrimaryColor(color: Int) { + dismissText.setTextColor(color) + if (!isDismissible) { + cancelText.setTextColor(color) + } + } + + fun setTextColor(color: Int) { + textColorFixed = color + gutsText.setTextColor(color) + settings.imageTintList = ColorStateList.valueOf(color) + + if (isDismissible) { + cancelText.setTextColor(color) + } } /** Sets the surface color on all guts views that use it. */ + @Deprecated("Remove with media_controls_a11y_colors") fun setSurfaceColor(surfaceColor: Int) { dismissText.setTextColor(surfaceColor) if (!isDismissible) { @@ -81,6 +117,7 @@ class GutsViewHolder constructor(itemView: View) { } /** Sets the primary accent color on all guts views that use it. */ + @Deprecated("Remove with media_controls_a11y_colors") fun setAccentPrimaryColor(accentPrimary: Int) { val accentColorList = ColorStateList.valueOf(accentPrimary) settings.imageTintList = accentColorList @@ -89,6 +126,7 @@ class GutsViewHolder constructor(itemView: View) { } /** Sets the primary text color on all guts views that use it. */ + @Deprecated("Remove with media_controls_a11y_colors") fun setTextPrimaryColor(textPrimary: Int) { val textColorList = ColorStateList.valueOf(textPrimary) gutsText.setTextColor(textColorList) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt index 61e4d95a88e6..bcda485272c2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt @@ -418,7 +418,11 @@ class MediaControlViewModel( ) const val TURBULENCE_NOISE_PLAY_MS_DURATION = 7500L - const val MEDIA_PLAYER_SCRIM_START_ALPHA = 0.25f - const val MEDIA_PLAYER_SCRIM_END_ALPHA = 1.0f + @Deprecated("Remove with media_controls_a11y_colors flag") + const val MEDIA_PLAYER_SCRIM_START_ALPHA_LEGACY = 0.25f + @Deprecated("Remove with media_controls_a11y_colors flag") + const val MEDIA_PLAYER_SCRIM_END_ALPHA_LEGACY = 1.0f + const val MEDIA_PLAYER_SCRIM_START_ALPHA = 0.65f + const val MEDIA_PLAYER_SCRIM_END_ALPHA = 0.75f } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java index 565b2e41f75a..ea4418427698 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java @@ -185,6 +185,7 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { mSubTitleText.setTextColor(mController.getColorItemContent()); mVolumeValueText.setTextColor(mController.getColorItemContent()); mIconAreaLayout.setBackground(null); + updateIconAreaClickListener(null); mSeekBar.setProgressTintList( ColorStateList.valueOf(mController.getColorSeekbarProgress())); enableFocusPropertyForView(mContainerLayout); @@ -392,6 +393,11 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { @Override public void onMute() { + mController.logInteractionMuteDevice(device); + } + + @Override + public void onUnmute() { mController.logInteractionUnmuteDevice(device); } }; @@ -430,6 +436,9 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { @Override public void onMute() {} + + @Override + public void onUnmute() {} }; if (!mController.isVolumeControlEnabledForSession()) { @@ -622,11 +631,13 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { private void updateFullItemClickListener(@Nullable View.OnClickListener listener) { mContainerLayout.setOnClickListener(listener); - updateIconAreaClickListener(listener); } void updateIconAreaClickListener(@Nullable View.OnClickListener listener) { mIconAreaLayout.setOnClickListener(listener); + if (listener == null) { + mIconAreaLayout.setClickable(false); // clickable is not removed automatically. + } } private void initAnimator() { @@ -677,6 +688,7 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { mSeekBar.setOnTouchListener((v, event) -> false); updateIconAreaClickListener((v) -> { if (volumeControl.getVolume() == 0) { + volumeControl.onUnmute(); mSeekBar.setVolume(UNMUTE_DEFAULT_VOLUME); volumeControl.setVolume(UNMUTE_DEFAULT_VOLUME); updateUnmutedVolumeIcon(null); @@ -713,6 +725,7 @@ public class MediaOutputAdapterLegacy extends MediaOutputAdapterBase { int getVolume(); void setVolume(int volume); void onMute(); + void onUnmute(); } private abstract class MediaSeekBarChangedListener diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt index 24bb16a11fe7..3a81102699f7 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt @@ -27,9 +27,7 @@ object QSEvents { private set fun setLoggerForTesting(): UiEventLoggerFake { - return UiEventLoggerFake().also { - qsUiEventsLogger = it - } + return UiEventLoggerFake().also { qsUiEventsLogger = it } } fun resetLogger() { @@ -40,32 +38,28 @@ object QSEvents { enum class QSEvent(private val _id: Int) : UiEventLogger.UiEventEnum { @UiEvent(doc = "Tile clicked. It has an instance id and a spec (or packageName)") QS_ACTION_CLICK(387), - - @UiEvent(doc = "Tile secondary button clicked. " + - "It has an instance id and a spec (or packageName)") + @UiEvent( + doc = + "Tile secondary button clicked. " + "It has an instance id and a spec (or packageName)" + ) QS_ACTION_SECONDARY_CLICK(388), - @UiEvent(doc = "Tile long clicked. It has an instance id and a spec (or packageName)") QS_ACTION_LONG_PRESS(389), - - @UiEvent(doc = "Quick Settings panel expanded") - QS_PANEL_EXPANDED(390), - - @UiEvent(doc = "Quick Settings panel collapsed") - QS_PANEL_COLLAPSED(391), - - @UiEvent(doc = "Tile visible in Quick Settings panel. The tile may be in a different page. " + - "It has an instance id and a spec (or packageName)") + @UiEvent(doc = "Quick Settings panel expanded") QS_PANEL_EXPANDED(390), + @UiEvent(doc = "Quick Settings panel collapsed") QS_PANEL_COLLAPSED(391), + @UiEvent( + doc = + "Tile visible in Quick Settings panel. The tile may be in a different page. " + + "It has an instance id and a spec (or packageName)" + ) QS_TILE_VISIBLE(392), - - @UiEvent(doc = "Quick Quick Settings panel expanded") - QQS_PANEL_EXPANDED(393), - - @UiEvent(doc = "Quick Quick Settings panel collapsed") - QQS_PANEL_COLLAPSED(394), - - @UiEvent(doc = "Tile visible in Quick Quick Settings panel. " + - "It has an instance id and a spec (or packageName)") + @UiEvent(doc = "Quick Quick Settings panel expanded") QQS_PANEL_EXPANDED(393), + @UiEvent(doc = "Quick Quick Settings panel collapsed") QQS_PANEL_COLLAPSED(394), + @UiEvent( + doc = + "Tile visible in Quick Quick Settings panel. " + + "It has an instance id and a spec (or packageName)" + ) QQS_TILE_VISIBLE(395); override fun getId() = _id @@ -73,47 +67,32 @@ enum class QSEvent(private val _id: Int) : UiEventLogger.UiEventEnum { enum class QSEditEvent(private val _id: Int) : UiEventLogger.UiEventEnum { - @UiEvent(doc = "Tile removed from current tiles") - QS_EDIT_REMOVE(210), - - @UiEvent(doc = "Tile added to current tiles") - QS_EDIT_ADD(211), - - @UiEvent(doc = "Tile moved") - QS_EDIT_MOVE(212), - - @UiEvent(doc = "QS customizer open") - QS_EDIT_OPEN(213), - - @UiEvent(doc = "QS customizer closed") - QS_EDIT_CLOSED(214), - - @UiEvent(doc = "QS tiles reset") - QS_EDIT_RESET(215); + @UiEvent(doc = "Tile removed from current tiles") QS_EDIT_REMOVE(210), + @UiEvent(doc = "Tile added to current tiles") QS_EDIT_ADD(211), + @UiEvent(doc = "Tile moved") QS_EDIT_MOVE(212), + @UiEvent(doc = "QS customizer open") QS_EDIT_OPEN(213), + @UiEvent(doc = "QS customizer closed") QS_EDIT_CLOSED(214), + @UiEvent(doc = "QS tiles reset") QS_EDIT_RESET(215), + @UiEvent(doc = "QS edit mode resize tile to large") QS_EDIT_RESIZE_LARGE(2122), + @UiEvent(doc = "QS edit mode resize tile to small") QS_EDIT_RESIZE_SMALL(2123); override fun getId() = _id } /** - * Events from the QS DND tile dialog. {@see QSZenModeDialogMetricsLogger} - * Other names for DND (Do Not Disturb) include "Zen" and "Priority mode". + * Events from the QS DND tile dialog. {@see QSZenModeDialogMetricsLogger} Other names for DND (Do + * Not Disturb) include "Zen" and "Priority mode". */ enum class QSDndEvent(private val _id: Int) : UiEventLogger.UiEventEnum { - @UiEvent(doc = "User selected an option on the DND dialog") - QS_DND_CONDITION_SELECT(420), - + @UiEvent(doc = "User selected an option on the DND dialog") QS_DND_CONDITION_SELECT(420), @UiEvent(doc = "User increased countdown duration of DND from the DND dialog") QS_DND_TIME_UP(422), - @UiEvent(doc = "User decreased countdown duration of DND from the DND dialog") QS_DND_TIME_DOWN(423), - @UiEvent(doc = "User enabled DND from the QS DND dialog to last until manually turned off") QS_DND_DIALOG_ENABLE_FOREVER(946), - @UiEvent(doc = "User enabled DND from the QS DND dialog to last until the next alarm goes off") QS_DND_DIALOG_ENABLE_UNTIL_ALARM(947), - @UiEvent(doc = "User enabled DND from the QS DND dialog to last until countdown is done") QS_DND_DIALOG_ENABLE_UNTIL_COUNTDOWN(948); @@ -121,29 +100,17 @@ enum class QSDndEvent(private val _id: Int) : UiEventLogger.UiEventEnum { } enum class QSUserSwitcherEvent(private val _id: Int) : UiEventLogger.UiEventEnum { - @UiEvent(doc = "The current user has been switched in the detail panel") - QS_USER_SWITCH(424), - - @UiEvent(doc = "User switcher QS dialog open") - QS_USER_DETAIL_OPEN(425), - - @UiEvent(doc = "User switcher QS dialog closed") - QS_USER_DETAIL_CLOSE(426), - - @UiEvent(doc = "User switcher QS dialog more settings pressed") - QS_USER_MORE_SETTINGS(427), - - @UiEvent(doc = "The user has added a guest in the detail panel") - QS_USER_GUEST_ADD(754), - + @UiEvent(doc = "The current user has been switched in the detail panel") QS_USER_SWITCH(424), + @UiEvent(doc = "User switcher QS dialog open") QS_USER_DETAIL_OPEN(425), + @UiEvent(doc = "User switcher QS dialog closed") QS_USER_DETAIL_CLOSE(426), + @UiEvent(doc = "User switcher QS dialog more settings pressed") QS_USER_MORE_SETTINGS(427), + @UiEvent(doc = "The user has added a guest in the detail panel") QS_USER_GUEST_ADD(754), @UiEvent(doc = "The user selected 'Start over' after switching to the existing Guest user") QS_USER_GUEST_WIPE(755), - @UiEvent(doc = "The user selected 'Yes, continue' after switching to the existing Guest user") QS_USER_GUEST_CONTINUE(756), - @UiEvent(doc = "The user has pressed 'Remove guest' in the detail panel") QS_USER_GUEST_REMOVE(757); override fun getId() = _id -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt index 28540d4f1259..6ad8bae05d7a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt @@ -53,6 +53,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment @@ -287,7 +288,7 @@ constructor( private fun CollapsableQuickSettingsSTL() { val sceneState = rememberMutableSceneTransitionLayoutState( - viewModel.expansionState.toIdleSceneKey(), + initialScene = remember { viewModel.expansionState.toIdleSceneKey() }, transitions = transitions { from(QuickQuickSettings, QuickSettings) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt index c09d319f82f5..ff84479ebcad 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt @@ -35,7 +35,6 @@ import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.classifier.Classifier import com.android.systemui.classifier.domain.interactor.FalsingInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor -import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.Edge @@ -43,7 +42,6 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.log.table.TableLogBuffer -import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QQS import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS import com.android.systemui.media.controls.ui.view.MediaHost @@ -101,7 +99,7 @@ constructor( private val footerActionsController: FooterActionsController, private val sysuiStatusBarStateController: SysuiStatusBarStateController, deviceEntryInteractor: DeviceEntryInteractor, - DisableFlagsInteractor: DisableFlagsInteractor, + disableFlagsInteractor: DisableFlagsInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, private val largeScreenShadeInterpolator: LargeScreenShadeInterpolator, shadeInteractor: ShadeInteractor, @@ -119,7 +117,7 @@ constructor( @Assisted private val lifecycleScope: LifecycleCoroutineScope, ) : Dumpable, ExclusiveActivatable() { - val containerViewModel = containerViewModelFactory.create(true) + val containerViewModel = containerViewModelFactory.create(supportsBrightnessMirroring = true) val quickQuickSettingsViewModel = quickQuickSettingsViewModelFactory.create() private val qqsMediaInRowViewModel = mediaInRowInLandscapeViewModelFactory.create(LOCATION_QQS) @@ -199,8 +197,8 @@ constructor( val isQsEnabled by hydrator.hydratedStateOf( traceName = "isQsEnabled", - initialValue = DisableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled(), - source = DisableFlagsInteractor.disableFlags.map { it.isQuickSettingsEnabled() }, + initialValue = disableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled(), + source = disableFlagsInteractor.disableFlags.map { it.isQuickSettingsEnabled() }, ) var isInSplitShade by mutableStateOf(false) @@ -490,12 +488,12 @@ constructor( qqsMediaHost.apply { expansion = qqsMediaExpansion showsOnlyActiveMedia = true - init(MediaHierarchyManager.LOCATION_QQS) + init(LOCATION_QQS) } qsMediaHost.apply { expansion = MediaHostState.EXPANDED showsOnlyActiveMedia = false - init(MediaHierarchyManager.LOCATION_QS) + init(LOCATION_QS) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt index 482cd4014acf..3f279b0f7a74 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt @@ -16,15 +16,18 @@ package com.android.systemui.qs.panels.domain.interactor +import com.android.internal.logging.UiEventLogger import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel +import com.android.systemui.qs.QSEditEvent import com.android.systemui.qs.panels.data.repository.DefaultLargeTilesRepository import com.android.systemui.qs.panels.data.repository.LargeTileSpanRepository import com.android.systemui.qs.panels.shared.model.PanelsLog import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.pipeline.shared.metricSpec import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted @@ -40,6 +43,7 @@ constructor( private val repo: DefaultLargeTilesRepository, private val currentTilesInteractor: CurrentTilesInteractor, private val preferencesInteractor: QSPreferencesInteractor, + private val uiEventLogger: UiEventLogger, largeTilesSpanRepo: LargeTileSpanRepository, @PanelsLog private val logBuffer: LogBuffer, @Application private val applicationScope: CoroutineScope, @@ -70,8 +74,18 @@ constructor( val isIcon = !largeTilesSpecs.value.contains(spec) if (toIcon && !isIcon) { preferencesInteractor.setLargeTilesSpecs(largeTilesSpecs.value - spec) + uiEventLogger.log( + /* event= */ QSEditEvent.QS_EDIT_RESIZE_SMALL, + /* uid= */ 0, + /* packageName= */ spec.metricSpec, + ) } else if (!toIcon && isIcon) { preferencesInteractor.setLargeTilesSpecs(largeTilesSpecs.value + spec) + uiEventLogger.log( + /* event= */ QSEditEvent.QS_EDIT_RESIZE_LARGE, + /* uid= */ 0, + /* packageName= */ spec.metricSpec, + ) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt index 302242ca11dd..eb6f97942ec0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/BounceableInfo.kt @@ -19,8 +19,6 @@ package com.android.systemui.qs.panels.ui.compose import androidx.compose.runtime.Stable import com.android.compose.animation.Bounceable import com.android.systemui.qs.panels.shared.model.SizedTile -import com.android.systemui.qs.panels.ui.model.GridCell -import com.android.systemui.qs.panels.ui.model.TileGridCell import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel @@ -32,18 +30,6 @@ data class BounceableInfo( val bounceEnd: Boolean, ) -fun List<Pair<GridCell, BounceableTileViewModel>>.bounceableInfo( - index: Int, - columns: Int, -): BounceableInfo { - val cell = this[index].first as TileGridCell - // Only look for neighbor bounceables if they are on the same row - val onLastColumn = cell.onLastColumn(cell.column, columns) - val previousTile = getOrNull(index - 1)?.takeIf { cell.column != 0 } - val nextTile = getOrNull(index + 1)?.takeIf { !onLastColumn } - return BounceableInfo(this[index].second, previousTile?.second, nextTile?.second, !onLastColumn) -} - fun List<BounceableTileViewModel>.bounceableInfo( sizedTile: SizedTile<TileViewModel>, index: Int, diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt index 1a7ef62a2e7c..a07120629d2b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt @@ -144,12 +144,17 @@ private fun FooterBar( pagerState: PagerState, editButtonViewModelFactory: EditModeButtonViewModel.Factory, ) { + val editButtonViewModel = + rememberViewModel(traceName = "PaginatedGridLayout-editButtonViewModel") { + editButtonViewModelFactory.create() + } + // Use requiredHeight so it won't be squished if the view doesn't quite fit. As this is // expected to be inside a scrollable container, this should not be an issue. // Also, we construct the layout this way to do the following: // * PagerDots is centered in the row, taking as much space as it needs. // * On the start side, we place the BuildNumber, taking as much space as it needs, but - // constrained by the available space left over after PagerDots + // constrained by the available space left over after PagerDots. // * On the end side, we place the edit mode button, with the same constraints as for // BuildNumber (but it will usually fit, as it's just a square button). Row( @@ -178,7 +183,7 @@ private fun FooterBar( ) Row(Modifier.weight(1f)) { Spacer(modifier = Modifier.weight(1f)) - EditModeButton(viewModelFactory = editButtonViewModelFactory) + EditModeButton(viewModel = editButtonViewModel) } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt index ebfe101948c2..ddadb8879f07 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt @@ -22,7 +22,6 @@ import androidx.compose.animation.AnimatedContent import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -34,7 +33,6 @@ import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.clipScrollableContainer import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Arrangement.spacedBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope @@ -47,28 +45,27 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredHeightIn import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.systemGestureExclusion import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Clear -import androidx.compose.material.icons.filled.Remove import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -91,12 +88,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.isSpecified import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.MeasureScope import androidx.compose.ui.layout.layout import androidx.compose.ui.layout.onGloballyPositioned @@ -113,24 +107,17 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.unit.toSize import androidx.compose.ui.util.fastMap -import androidx.compose.ui.zIndex -import com.android.app.tracing.coroutines.launchTraced as launch -import com.android.compose.animation.bounceable import com.android.compose.modifiers.height import com.android.systemui.common.ui.compose.load import com.android.systemui.qs.panels.shared.model.SizedTile import com.android.systemui.qs.panels.shared.model.SizedTileImpl -import com.android.systemui.qs.panels.ui.compose.BounceableInfo import com.android.systemui.qs.panels.ui.compose.DragAndDropState import com.android.systemui.qs.panels.ui.compose.DragType import com.android.systemui.qs.panels.ui.compose.EditTileListState -import com.android.systemui.qs.panels.ui.compose.bounceableInfo import com.android.systemui.qs.panels.ui.compose.dragAndDropRemoveZone import com.android.systemui.qs.panels.ui.compose.dragAndDropTileList import com.android.systemui.qs.panels.ui.compose.dragAndDropTileSource @@ -142,13 +129,14 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaul import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AUTO_SCROLL_SPEED import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.AvailableTilesGridMinHeight import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.CurrentTilesGridPadding -import com.android.systemui.qs.panels.ui.compose.infinitegrid.EditModeTileDefaults.TileBadgeSize +import com.android.systemui.qs.panels.ui.compose.selection.InteractiveTileContainer import com.android.systemui.qs.panels.ui.compose.selection.MutableSelectionState -import com.android.systemui.qs.panels.ui.compose.selection.ResizableTileContainer import com.android.systemui.qs.panels.ui.compose.selection.ResizingState import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.FinalResizeOperation import com.android.systemui.qs.panels.ui.compose.selection.ResizingState.ResizeOperation.TemporaryResizeOperation +import com.android.systemui.qs.panels.ui.compose.selection.StaticTileBadge +import com.android.systemui.qs.panels.ui.compose.selection.TileState import com.android.systemui.qs.panels.ui.compose.selection.rememberResizingState import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState import com.android.systemui.qs.panels.ui.compose.selection.selectableTile @@ -252,13 +240,15 @@ fun DefaultEditTileGrid( AnimatedContent( targetState = listState.dragInProgress || selectionState.selected, label = "QSEditHeader", + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxWidth().heightIn(min = 80.dp), ) { showRemoveTarget -> - EditGridHeader(Modifier.padding(bottom = 26.dp)) { + EditGridHeader { if (showRemoveTarget) { RemoveTileTarget { selectionState.selection?.let { selectionState.unSelect() - onRemoveTile(it.tileSpec) + onRemoveTile(it) } } } else { @@ -380,7 +370,7 @@ private fun RemoveTileTarget(onClick: () -> Unit) { verticalAlignment = Alignment.CenterVertically, horizontalArrangement = tileHorizontalArrangement(), modifier = - Modifier.fillMaxHeight() + Modifier.wrapContentSize() .clickable(onClick = onClick) .border(1.dp, LocalContentColor.current, shape = CircleShape) .padding(10.dp), @@ -430,22 +420,15 @@ private fun CurrentTilesGrid( ) .dragAndDropTileList(gridState, { gridContentOffset }, listState) { spec -> onSetTiles(currentListState.tileSpecs()) - selectionState.select(spec, manual = false) + selectionState.select(spec) } .onGloballyPositioned { coordinates -> gridContentOffset = coordinates.positionInRoot() } .testTag(CURRENT_TILES_GRID_TEST_TAG), ) { - EditTiles( - cells, - columns, - listState, - selectionState, - coroutineScope, - largeTilesSpan, - onRemoveTile, - ) { resizingOperation -> + EditTiles(cells, listState, selectionState, coroutineScope, largeTilesSpan, onRemoveTile) { + resizingOperation -> when (resizingOperation) { is TemporaryResizeOperation -> { currentListState.resizeTile(resizingOperation.spec, resizingOperation.toIcon) @@ -453,10 +436,6 @@ private fun CurrentTilesGrid( is FinalResizeOperation -> { // Commit the new size of the tile onResize(resizingOperation.spec, resizingOperation.toIcon) - - // Mark the selection as automatic in case the tile ends up moving to a - // different row with its new size. - selectionState.select(resizingOperation.spec, manual = false) } } } @@ -536,7 +515,6 @@ private fun GridCell.key(index: Int): Any { * Adds a list of [GridCell] to the lazy grid * * @param cells the pairs of [GridCell] to [BounceableTileViewModel] - * @param columns the number of columns of this tile grid * @param dragAndDropState the [DragAndDropState] for this grid * @param selectionState the [MutableSelectionState] for this grid * @param coroutineScope the [CoroutineScope] to be used for the tiles @@ -545,7 +523,6 @@ private fun GridCell.key(index: Int): Any { */ fun LazyGridScope.EditTiles( cells: List<Pair<GridCell, BounceableTileViewModel>>, - columns: Int, dragAndDropState: DragAndDropState, selectionState: MutableSelectionState, coroutineScope: CoroutineScope, @@ -581,7 +558,6 @@ fun LazyGridScope.EditTiles( onResize = onResize, onRemoveTile = onRemoveTile, coroutineScope = coroutineScope, - bounceableInfo = cells.bounceableInfo(index, columns), largeTilesSpan = largeTilesSpan, modifier = Modifier.animateItem(), ) @@ -601,83 +577,84 @@ private fun TileGridCell( onRemoveTile: (TileSpec) -> Unit, coroutineScope: CoroutineScope, largeTilesSpan: Int, - bounceableInfo: BounceableInfo, modifier: Modifier = Modifier, ) { val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1) - var selected by remember { mutableStateOf(false) } - val showRemovalBadge = - !selected && cell.tile.availableEditActions.contains(AvailableEditActions.REMOVE) - val selectionAlpha by - animateFloatAsState( - targetValue = if (selected) 1f else 0f, - label = "QSEditTileSelectionAlpha", - ) - val selectionColor = MaterialTheme.colorScheme.primary - val colors = EditModeTileDefaults.editTileColors() - val currentBounceableInfo by rememberUpdatedState(bounceableInfo) - - LaunchedEffect(selectionState.selection?.tileSpec) { - selectionState.selection?.let { - // A delay is introduced on automatic selections such as dragged tiles or reflow caused - // by resizing. This avoids clipping issues on the border and resizing handle, as well - // as letting the selection animation play correctly. - if (!it.manual) { - delay(250) + val canShowRemovalBadge = cell.tile.availableEditActions.contains(AvailableEditActions.REMOVE) + var tileState by remember { mutableStateOf(TileState.None) } + + LaunchedEffect(selectionState.selection, canShowRemovalBadge) { + tileState = + when { + selectionState.selection == cell.tile.tileSpec -> { + if (tileState == TileState.None && canShowRemovalBadge) { + // The tile decoration is None if a tile is newly composed OR the removal + // badge can't be shown. + // For newly composed and selected tiles, such as dragged tiles or moved + // tiles from resizing, introduce a short delay. This avoids clipping issues + // on the border and resizing handle, as well as letting the selection + // animation play correctly. + delay(250) + } + TileState.Selected + } + canShowRemovalBadge -> TileState.Removable + else -> TileState.None } - } - selected = selectionState.selection?.tileSpec == cell.tile.tileSpec } - val state = rememberResizingState(cell.tile.tileSpec, cell.isIcon) - + val resizingState = rememberResizingState(cell.tile.tileSpec, cell.isIcon) val progress: () -> Float = { - if (selected) { - // If selected, return the manual progress from the drag - state.progress() + if (tileState == TileState.Selected) { + resizingState.progress() } else { - // Else, return the target progress for the tile format if (cell.isIcon) 0f else 1f } } - if (!selected) { + if (tileState != TileState.Selected) { // Update the draggable anchor state when the tile's size is not manually toggled - LaunchedEffect(cell.isIcon) { state.updateCurrentValue(cell.isIcon) } + LaunchedEffect(cell.isIcon) { resizingState.updateCurrentValue(cell.isIcon) } } else { // If the tile is selected, listen to new target values from the draggable anchor to toggle // the tile's size - LaunchedEffect(state.temporaryResizeOperation) { onResize(state.temporaryResizeOperation) } - LaunchedEffect(state.finalResizeOperation) { onResize(state.finalResizeOperation) } + LaunchedEffect(resizingState.temporaryResizeOperation) { + onResize(resizingState.temporaryResizeOperation) + } + LaunchedEffect(resizingState.finalResizeOperation) { + onResize(resizingState.finalResizeOperation) + } } val totalPadding = with(LocalDensity.current) { (largeTilesSpan - 1) * TileArrangementPadding.roundToPx() } - - ResizableTileContainer( - selected = selected, - state = state, - selectionAlpha = { selectionAlpha }, - selectionColor = selectionColor, + val colors = EditModeTileDefaults.editTileColors() + val toggleSizeLabel = stringResource(R.string.accessibility_qs_edit_toggle_tile_size_action) + val clickLabel = + when (tileState) { + TileState.None -> null + TileState.Removable -> + stringResource(id = R.string.accessibility_qs_edit_remove_tile_action) + TileState.Selected -> toggleSizeLabel + } + InteractiveTileContainer( + tileState = tileState, + resizingState = resizingState, modifier = - modifier - .height(TileHeight) - .fillMaxWidth() - .onSizeChanged { - // Grab the size before the bounceable to get the idle width - val min = - if (cell.isIcon) it.width else (it.width - totalPadding) / largeTilesSpan - val max = - if (cell.isIcon) (it.width * largeTilesSpan) + totalPadding else it.width - state.updateAnchors(min.toFloat(), max.toFloat()) - } - .bounceable( - bounceable = currentBounceableInfo.bounceable, - previousBounceable = currentBounceableInfo.previousTile, - nextBounceable = currentBounceableInfo.nextTile, - orientation = Orientation.Horizontal, - bounceEnd = currentBounceableInfo.bounceEnd, - ), + modifier.height(TileHeight).fillMaxWidth().onSizeChanged { + // Calculate the min/max width from the idle size + val min = if (cell.isIcon) it.width else (it.width - totalPadding) / largeTilesSpan + val max = if (cell.isIcon) (it.width * largeTilesSpan) + totalPadding else it.width + resizingState.updateAnchors(min.toFloat(), max.toFloat()) + }, + onClick = { + if (tileState == TileState.Removable) { + onRemoveTile(cell.tile.tileSpec) + } else if (tileState == TileState.Selected) { + coroutineScope.launch { resizingState.toggleCurrentValue() } + } + }, + onClickLabel = clickLabel, ) { Box( modifier @@ -688,15 +665,13 @@ private fun TileGridCell( customActions = listOf( // TODO(b/367748260): Add final accessibility actions - CustomAccessibilityAction("Toggle size") { + CustomAccessibilityAction(toggleSizeLabel) { onResize(FinalResizeOperation(cell.tile.tileSpec, !cell.isIcon)) true } ) } - .selectableTile(cell.tile.tileSpec, selectionState) { - coroutineScope.launch { currentBounceableInfo.bounceable.animateBounce() } - } + .selectableTile(cell.tile.tileSpec, selectionState) .dragAndDropTileSource( SizedTileImpl(cell.tile, cell.width), dragAndDropState, @@ -705,16 +680,7 @@ private fun TileGridCell( ) .tileBackground(colors.background) ) { - EditTile(tile = cell.tile, state = state, progress = progress) - } - - if (showRemovalBadge) { - TileBadge( - icon = Icons.Default.Remove, - contentDescription = stringResource(R.string.qs_customize_remove), - ) { - onRemoveTile(cell.tile.tileSpec) - } + EditTile(tile = cell.tile, state = resizingState, progress = progress) } } } @@ -733,7 +699,7 @@ private fun AvailableTileGridCell( val colors = EditModeTileDefaults.editTileColors() val onClick = { onAddTile(cell.tile.tileSpec) - selectionState.select(cell.tile.tileSpec, manual = false) + selectionState.select(cell.tile.tileSpec) } // Displays the tile as an icon tile with the label underneath @@ -742,10 +708,9 @@ private fun AvailableTileGridCell( verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top), modifier = modifier, ) { - Box { + Box(Modifier.fillMaxWidth().height(TileHeight)) { Box( - Modifier.fillMaxWidth() - .height(TileHeight) + Modifier.fillMaxSize() .clickable(onClick = onClick, onClickLabel = onClickActionName) .semantics(mergeDescendants = true) { this.stateDescription = stateDescription } .dragAndDropTileSource( @@ -756,7 +721,6 @@ private fun AvailableTileGridCell( selectionState.unSelect() } .tileBackground(colors.background) - .tilePadding() ) { // Icon SmallTileContent( @@ -767,7 +731,7 @@ private fun AvailableTileGridCell( ) } - TileBadge( + StaticTileBadge( icon = Icons.Default.Add, contentDescription = onClickActionName, onClick = onClick, @@ -787,39 +751,6 @@ private fun AvailableTileGridCell( } @Composable -private fun TileBadge(icon: ImageVector, contentDescription: String?, onClick: () -> Unit) { - // Use a higher zIndex than the tile to draw over it, and manually create the touch target as - // we're drawing over neighbor tiles as well. - val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current - - Box( - Modifier.zIndex(2f) - .layout { measurable, constraints -> - val size = minTouchTargetSize.roundToPx() - val placeable = measurable.measure(Constraints(size)) - layout(placeable.width, placeable.height) { - val iconRadius = TileBadgeSize.roundToPx() / 2 - val x = constraints.maxWidth - placeable.width / 2 - iconRadius - val y = 0 - placeable.height / 2 + iconRadius - placeable.place(x, y) - } - } - .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) } - .pointerInput(Unit) { detectTapGestures { onClick() } } - ) { - val secondaryColor = MaterialTheme.colorScheme.secondary - Icon( - icon, - contentDescription = contentDescription, - modifier = - Modifier.size(TileBadgeSize).align(Alignment.Center).drawBehind { - drawCircle(secondaryColor) - }, - ) - } -} - -@Composable private fun SpacerGridCell(modifier: Modifier = Modifier) { // By default, spacers are invisible and exist purely to catch drag movements Box(modifier.height(TileHeight).fillMaxWidth()) @@ -902,9 +833,8 @@ private object EditModeTileDefaults { const val PLACEHOLDER_ALPHA = .3f const val AUTO_SCROLL_DISTANCE = 100 const val AUTO_SCROLL_SPEED = 2 // 2ms per pixel - val CurrentTilesGridPadding = 8.dp + val CurrentTilesGridPadding = 10.dp val AvailableTilesGridMinHeight = 200.dp - val TileBadgeSize = 20.dp @Composable fun editTileColors(): TileColors = diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt index 47238d176b36..d73dc870756b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt @@ -245,6 +245,7 @@ private fun TileExpandable( color = color(), shape = shape, modifier = modifier.clip(shape).verticalSquish(squishiness), + useModifierBasedImplementation = true, ) { content(hapticsViewModel?.createStateAwareExpandable(it) ?: it) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt index 26dfc7224ff9..3dfde86bf8d9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionState.kt @@ -32,23 +32,17 @@ fun rememberSelectionState(): MutableSelectionState { return remember { MutableSelectionState() } } -/** - * Holds the selected [TileSpec] and whether the selection was manual, i.e. caused by a tap from the - * user. - */ -data class Selection(val tileSpec: TileSpec, val manual: Boolean) - /** Holds the state of the current selection. */ class MutableSelectionState { - /** The [Selection] if a tile is selected, null if not. */ - var selection by mutableStateOf<Selection?>(null) + /** The [TileSpec] of a tile is selected, null if not. */ + var selection by mutableStateOf<TileSpec?>(null) private set val selected: Boolean get() = selection != null - fun select(tileSpec: TileSpec, manual: Boolean) { - selection = Selection(tileSpec, manual) + fun select(tileSpec: TileSpec) { + selection = tileSpec } fun unSelect() { @@ -68,10 +62,10 @@ fun Modifier.selectableTile( return pointerInput(Unit) { detectTapGestures( onTap = { - if (selectionState.selection?.tileSpec == tileSpec) { + if (selectionState.selection == tileSpec) { selectionState.unSelect() } else { - selectionState.select(tileSpec, manual = true) + selectionState.select(tileSpec) } onClick() } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt index 7c472638da63..699e5f6b77e9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt @@ -16,141 +16,232 @@ package com.android.systemui.qs.panels.ui.compose.selection -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.core.spring -import androidx.compose.foundation.Canvas +import androidx.compose.animation.animateColor +import androidx.compose.animation.core.Transition +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.animateOffset +import androidx.compose.animation.core.animateSize +import androidx.compose.animation.core.updateTransition import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.gestures.anchoredDraggable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.foundation.systemGestureExclusion +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Remove +import androidx.compose.material3.Icon import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.geometry.center import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.layout +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.toSize import androidx.compose.ui.zIndex +import com.android.compose.modifiers.size import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius -import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingDotSize +import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BADGE_ANGLE_RAD +import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeSize +import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeXOffset +import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeYOffset +import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.RESIZING_PILL_ANGLE_RAD +import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingPillHeight +import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.ResizingPillWidth import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.SelectedBorderWidth +import com.android.systemui.qs.panels.ui.compose.selection.TileState.None +import com.android.systemui.qs.panels.ui.compose.selection.TileState.Removable +import com.android.systemui.qs.panels.ui.compose.selection.TileState.Selected +import kotlin.math.cos import kotlin.math.roundToInt -import kotlinx.coroutines.launch +import kotlin.math.sin /** - * Places a dot to handle resizing drag events. Use this on tiles to resize. + * Draws a tile decoration and handles click and drag events for them. * - * The dot is placed vertically centered on the right border. The [content] will have a border when - * selected. + * In states: + * - [TileState.Removable]: removal icon shown in the top end + * - [TileState.Selected]: pill shaped handle shown on the end border, as well as a colored border + * around the content. + * - [TileState.None]: nothing * - * @param selected whether resizing drag events should be handled - * @param state the [ResizingState] for the tile - * @param selectionAlpha the animated value for the dot and border alpha - * @param selectionColor the [Color] of the dot and border + * @param tileState the state for the tile decoration + * @param resizingState the [ResizingState] for the tile + * @param onClick the callback when the tile decoration is clicked */ @Composable -fun ResizableTileContainer( - selected: Boolean, - state: ResizingState, - selectionAlpha: () -> Float, - selectionColor: Color, +fun InteractiveTileContainer( + tileState: TileState, + resizingState: ResizingState, modifier: Modifier = Modifier, + onClick: () -> Unit = {}, + onClickLabel: String? = null, content: @Composable BoxScope.() -> Unit = {}, ) { - Box(modifier.resizable(selected, state).selectionBorder(selectionColor, selectionAlpha)) { - content() - ResizingHandle( - enabled = selected, - state = state, - modifier = - // Higher zIndex to make sure the handle is drawn above the content - Modifier.zIndex(if (selected) 2f else 1f), - ) - } -} + val transition: Transition<TileState> = updateTransition(tileState) + val decorationColor by transition.animateColor() + val decorationAngle by transition.animateAngle() + val decorationSize by transition.animateSize() + val decorationOffset by transition.animateOffset() + val decorationAlpha by transition.animateFloat { state -> if (state == None) 0f else 1f } + val badgeIconAlpha by transition.animateFloat { state -> if (state == Removable) 1f else 0f } + val selectionBorderAlpha by + transition.animateFloat { state -> if (state == Selected) 1f else 0f } -@Composable -private fun ResizingHandle(enabled: Boolean, state: ResizingState, modifier: Modifier = Modifier) { - // Manually creating the touch target around the resizing dot to ensure that the next tile - // does not receive the touch input accidentally. - val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current - val scope = rememberCoroutineScope() Box( - modifier - .layout { measurable, constraints -> - val size = minTouchTargetSize.roundToPx() - val placeable = measurable.measure(Constraints(size, size, size, size)) - layout(placeable.width, placeable.height) { - placeable.place( - x = constraints.maxWidth - placeable.width / 2, - y = constraints.maxHeight / 2 - placeable.height / 2, - ) - } - } - .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) } - .anchoredDraggable( - enabled = enabled, - state = state.anchoredDraggableState, - orientation = Orientation.Horizontal, - ) - .clickable(enabled = enabled, interactionSource = null, indication = null) { - scope.launch { state.toggleCurrentValue() } - } + modifier.resizable(tileState == Selected, resizingState).selectionBorder( + MaterialTheme.colorScheme.primary, + SelectedBorderWidth, + ) { + selectionBorderAlpha + } ) { - ResizingDot(enabled = enabled, modifier = Modifier.align(Alignment.Center)) - } -} + content() -@Composable -private fun ResizingDot( - enabled: Boolean, - modifier: Modifier = Modifier, - color: Color = MaterialTheme.colorScheme.primary, -) { - val alpha by animateFloatAsState(if (enabled) 1f else 0f) - val radius by - animateDpAsState( - if (enabled) ResizingDotSize / 2 else 0.dp, - animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy), - ) - Canvas(modifier = modifier.size(ResizingDotSize)) { - drawCircle(color = color, radius = radius.toPx(), alpha = alpha) + MinimumInteractiveSizeComponent( + angle = { decorationAngle }, + offset = { decorationOffset }, + ) { + Box( + Modifier.fillMaxSize() + .drawBehind { + drawRoundRect( + color = decorationColor, + topLeft = center - decorationSize.center, + size = decorationSize, + cornerRadius = CornerRadius(size.width / 2), + ) + } + .graphicsLayer { this.alpha = decorationAlpha } + .anchoredDraggable( + enabled = tileState == Selected, + state = resizingState.anchoredDraggableState, + orientation = Orientation.Horizontal, + ) + .clickable( + enabled = tileState != None, + interactionSource = null, + indication = null, + onClickLabel = onClickLabel, + onClick = onClick, + ) + ) { + Icon( + Icons.Default.Remove, + contentDescription = null, + modifier = + Modifier.size( + width = { decorationSize.width.roundToInt() }, + height = { decorationSize.height.roundToInt() }, + ) + .align(Alignment.Center) + .graphicsLayer { this.alpha = badgeIconAlpha }, + ) + } + } } } private fun Modifier.selectionBorder( selectionColor: Color, + selectionBorderWidth: Dp, selectionAlpha: () -> Float = { 0f }, ): Modifier { return drawWithContent { drawContent() + + // Draw the border on the inside of the tile + val borderWidth = selectionBorderWidth.toPx() drawRoundRect( SolidColor(selectionColor), cornerRadius = CornerRadius(InactiveCornerRadius.toPx()), - style = Stroke(SelectedBorderWidth.toPx()), + topLeft = Offset(borderWidth / 2, borderWidth / 2), + size = Size(size.width - borderWidth, size.height - borderWidth), + style = Stroke(borderWidth), alpha = selectionAlpha(), ) } } @Composable +fun StaticTileBadge(icon: ImageVector, contentDescription: String?, onClick: () -> Unit) { + val offset = with(LocalDensity.current) { Offset(BadgeXOffset.toPx(), BadgeYOffset.toPx()) } + MinimumInteractiveSizeComponent(angle = { BADGE_ANGLE_RAD }, offset = { offset }) { + Box( + Modifier.fillMaxSize() + .clickable( + interactionSource = null, + indication = null, + onClickLabel = contentDescription, + onClick = onClick, + ) + ) { + val secondaryColor = MaterialTheme.colorScheme.secondary + Icon( + icon, + contentDescription = contentDescription, + modifier = + Modifier.size(BadgeSize).align(Alignment.Center).drawBehind { + drawCircle(secondaryColor) + }, + ) + } + } +} + +@Composable +private fun MinimumInteractiveSizeComponent( + angle: () -> Float, + offset: () -> Offset, + content: @Composable BoxScope.() -> Unit, +) { + // Use a higher zIndex than the tile to draw over it, and manually create the touch target + // as we're drawing over neighbor tiles as well. + val minTouchTargetSize = LocalMinimumInteractiveComponentSize.current + Box( + contentAlignment = Alignment.Center, + modifier = + Modifier.zIndex(2f) + .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) } + .layout { measurable, constraints -> + val size = minTouchTargetSize.roundToPx() + val placeable = measurable.measure(Constraints.fixed(size, size)) + layout(placeable.width, placeable.height) { + val radius = constraints.maxHeight / 2f + val rotationCenter = Offset(constraints.maxWidth - radius, radius) + val position = offsetForAngle(angle(), radius, rotationCenter) + offset() + placeable.place( + position.x.roundToInt() - placeable.width / 2, + position.y.roundToInt() - placeable.height / 2, + ) + } + }, + content = content, + ) +} + +@Composable private fun Modifier.resizable(selected: Boolean, state: ResizingState): Modifier { if (!selected) return zIndex(1f) @@ -165,7 +256,69 @@ private fun Modifier.resizable(selected: Boolean, state: ResizingState): Modifie } } +enum class TileState { + None, + Removable, + Selected, +} + +@Composable +private fun Transition<TileState>.animateColor(): State<Color> { + return animateColor { state -> + when (state) { + None -> Color.Transparent + Removable -> MaterialTheme.colorScheme.secondary + Selected -> MaterialTheme.colorScheme.primary + } + } +} + +@Composable +private fun Transition<TileState>.animateAngle(): State<Float> { + return animateFloat { state -> + if (state == Removable) BADGE_ANGLE_RAD else RESIZING_PILL_ANGLE_RAD + } +} + +@Composable +private fun Transition<TileState>.animateSize(): State<Size> { + return animateSize { state -> + with(LocalDensity.current) { + when (state) { + None -> Size.Zero + Removable -> Size(BadgeSize.toPx()) + Selected -> Size(ResizingPillWidth.toPx(), ResizingPillHeight.toPx()) + } + } + } +} + +@Composable +private fun Transition<TileState>.animateOffset(): State<Offset> { + return animateOffset { state -> + with(LocalDensity.current) { + when (state) { + None -> Offset.Zero + Removable -> Offset(BadgeXOffset.toPx(), BadgeYOffset.toPx()) + Selected -> Offset(-SelectedBorderWidth.toPx(), 0f) + } + } + } +} + +private fun Size(size: Float) = Size(size, size) + +private fun offsetForAngle(angle: Float, radius: Float, center: Offset): Offset { + return Offset(x = radius * cos(angle) + center.x, y = radius * sin(angle) + center.y) +} + private object SelectionDefaults { - val ResizingDotSize = 16.dp val SelectedBorderWidth = 2.dp + val BadgeSize = 24.dp + val BadgeXOffset = -4.dp + val BadgeYOffset = 4.dp + val ResizingPillWidth = 8.dp + val ResizingPillHeight = 16.dp + const val BADGE_ANGLE_RAD = -.8f + const val RESIZING_PILL_ANGLE_RAD = 0f } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt index f3c06a481fc2..dc02fbb882af 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/EditModeButton.kt @@ -29,17 +29,12 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.qs.panels.ui.viewmodel.toolbar.EditModeButtonViewModel import com.android.systemui.qs.ui.compose.borderOnFocus import com.android.systemui.res.R @Composable -fun EditModeButton( - viewModelFactory: EditModeButtonViewModel.Factory, - modifier: Modifier = Modifier, -) { - val viewModel = rememberViewModel(traceName = "EditModeButton") { viewModelFactory.create() } +fun EditModeButton(viewModel: EditModeButtonViewModel, modifier: Modifier = Modifier) { CompositionLocalProvider( value = LocalContentColor provides MaterialTheme.colorScheme.onSurface ) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt index 59c554c28df6..360266a31be3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt @@ -22,28 +22,32 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.android.systemui.compose.modifiers.sysuiResTag -import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.qs.footer.ui.compose.IconButton import com.android.systemui.qs.panels.ui.viewmodel.toolbar.ToolbarViewModel @Composable -fun Toolbar(toolbarViewModelFactory: ToolbarViewModel.Factory, modifier: Modifier = Modifier) { - val viewModel = rememberViewModel("Toolbar") { toolbarViewModelFactory.create() } - +fun Toolbar(viewModel: ToolbarViewModel, modifier: Modifier = Modifier) { Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) { viewModel.userSwitcherViewModel?.let { - IconButton(it, Modifier.sysuiResTag("multi_user_switch")) + IconButton( + it, + useModifierBasedExpandable = true, + Modifier.sysuiResTag("multi_user_switch"), + ) } - EditModeButton(viewModel.editModeButtonViewModelFactory) + EditModeButton(viewModel.editModeButtonViewModel) IconButton( viewModel.settingsButtonViewModel, + useModifierBasedExpandable = true, Modifier.sysuiResTag("settings_button_container"), ) Spacer(modifier = Modifier.weight(1f)) - viewModel.powerButtonViewModel?.let { IconButton(it, Modifier.sysuiResTag("pm_lite")) } + viewModel.powerButtonViewModel?.let { + IconButton(it, useModifierBasedExpandable = true, Modifier.sysuiResTag("pm_lite")) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/dialog/QSResetDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/dialog/QSResetDialogDelegate.kt index cbece2cbb382..d2666006db92 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/dialog/QSResetDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/dialog/QSResetDialogDelegate.kt @@ -28,6 +28,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dialog.ui.composable.AlertDialogContent import com.android.systemui.qs.panels.domain.interactor.EditTilesResetInteractor import com.android.systemui.res.R +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.statusbar.phone.ComponentSystemUIDialog import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.phone.SystemUIDialogFactory @@ -40,6 +41,7 @@ class QSResetDialogDelegate @Inject constructor( private val sysuiDialogFactory: SystemUIDialogFactory, + private val shadeDialogContextInteractor: ShadeDialogContextInteractor, private val resetInteractor: EditTilesResetInteractor, ) : SystemUIDialog.Delegate { private var currentDialog: ComponentSystemUIDialog? = null @@ -53,7 +55,9 @@ constructor( currentDialog = sysuiDialogFactory - .create { ResetConfirmationDialog(it) } + .create(context = shadeDialogContextInteractor.context) { + ResetConfirmationDialog(it) + } .also { it.lifecycle.addObserver( object : DefaultLifecycleObserver { diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt index 2082423f1fd3..31323c749238 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/EditModeViewModel.kt @@ -42,6 +42,8 @@ import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -53,6 +55,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class EditModeViewModel @Inject @@ -73,11 +76,9 @@ constructor( private val _isEditing = MutableStateFlow(false) /** - * Whether we should be editing right now. Use [startEditing] and [stopEditing] to change this + * Whether we should be editing right now. Use [startEditing] and [stopEditing] to change this. */ val isEditing = _isEditing.asStateFlow() - private val minimumTiles: Int - get() = minTilesInteractor.minNumberOfTiles val gridLayout: StateFlow<GridLayout> = gridLayoutTypeInteractor.layout @@ -99,7 +100,7 @@ constructor( * * Tiles that are not available will be filtered out. None of them can be current (as they * cannot be created), and they won't be able to be added. */ - val tiles = + val tiles: Flow<List<EditTileViewModel>> = isEditing.flatMapLatest { if (it) { val editTilesData = editTilesListInteractor.getTilesToEdit() @@ -114,10 +115,10 @@ constructor( currentTilesInteractor.currentTiles .map { tiles -> val currentSpecs = tiles.map { it.spec } - val canRemoveTiles = currentSpecs.size > minimumTiles + val canRemoveTiles = currentSpecs.size > minTilesInteractor.minNumberOfTiles val allTiles = editTilesData.stockTiles + editTilesData.customTiles - val allTilesMap = allTiles.associate { it.tileSpec to it } - val currentTiles = currentSpecs.map { allTilesMap.get(it) }.filterNotNull() + val allTilesMap = allTiles.associateBy { it.tileSpec } + val currentTiles = currentSpecs.mapNotNull { allTilesMap[it] } val nonCurrentTiles = allTiles.filter { it.tileSpec !in currentSpecs } (currentTiles + nonCurrentTiles) diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt index fe5eec848dd8..846e06846437 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/PaginatedGridViewModel.kt @@ -16,7 +16,6 @@ package com.android.systemui.qs.panels.ui.viewmodel -import androidx.compose.runtime.getValue import com.android.systemui.classifier.Classifier.QS_SWIPE_SIDE import com.android.systemui.classifier.domain.interactor.FalsingInteractor import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt index 1a6653c38f9f..e54bfa29d2db 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/viewmodel/toolbar/ToolbarViewModel.kt @@ -45,7 +45,7 @@ import kotlinx.coroutines.launch class ToolbarViewModel @AssistedInject constructor( - val editModeButtonViewModelFactory: EditModeButtonViewModel.Factory, + editModeButtonViewModelFactory: EditModeButtonViewModel.Factory, private val footerActionsInteractor: FooterActionsInteractor, private val globalActionsDialogLiteProvider: Provider<GlobalActionsDialogLite>, private val falsingInteractor: FalsingInteractor, @@ -83,6 +83,8 @@ constructor( ), ) + val editModeButtonViewModel: EditModeButtonViewModel = editModeButtonViewModelFactory.create() + override suspend fun onActivated(): Nothing { coroutineScope { launch { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt index d0f258052f04..76ff88506fb6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegate.kt @@ -16,7 +16,6 @@ package com.android.systemui.qs.tiles.impl.saver.domain -import android.content.Context import android.content.DialogInterface import android.content.SharedPreferences import android.os.Bundle @@ -24,7 +23,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch import com.android.internal.R import com.android.systemui.coroutines.newTracingContext import com.android.systemui.qs.tiles.impl.saver.domain.interactor.DataSaverTileUserActionInteractor -import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.policy.DataSaverController import kotlin.coroutines.CoroutineContext @@ -32,13 +31,13 @@ import kotlinx.coroutines.CoroutineScope class DataSaverDialogDelegate( private val sysuiDialogFactory: SystemUIDialog.Factory, - @ShadeDisplayAware private val context: Context, + private val contextInteractor: ShadeDialogContextInteractor, private val backgroundContext: CoroutineContext, private val dataSaverController: DataSaverController, private val sharedPreferences: SharedPreferences, ) : SystemUIDialog.Delegate { override fun createDialog(): SystemUIDialog { - return sysuiDialogFactory.create(this, context) + return sysuiDialogFactory.create(this, contextInteractor.context) } override fun beforeCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt index 05bdf0a92679..63a9f594b05c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileUserActionInteractor.kt @@ -22,7 +22,6 @@ import android.provider.Settings import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogTransitionAnimator -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler @@ -33,6 +32,7 @@ import com.android.systemui.qs.tiles.impl.saver.domain.model.DataSaverTileModel import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import com.android.systemui.settings.UserFileManager import com.android.systemui.shade.ShadeDisplayAware +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.policy.DataSaverController import javax.inject.Inject @@ -44,6 +44,7 @@ class DataSaverTileUserActionInteractor @Inject constructor( @ShadeDisplayAware private val context: Context, + private val contextInteractor: ShadeDialogContextInteractor, @Main private val coroutineContext: CoroutineContext, @Background private val backgroundContext: CoroutineContext, private val dataSaverController: DataSaverController, @@ -79,18 +80,19 @@ constructor( val dialogDelegate = DataSaverDialogDelegate( systemUIDialogFactory, - context, + contextInteractor, backgroundContext, dataSaverController, - sharedPreferences + sharedPreferences, ) - val dialog = systemUIDialogFactory.create(dialogDelegate, context) + val dialog = + systemUIDialogFactory.create(dialogDelegate, contextInteractor.context) action.expandable ?.dialogTransitionController( DialogCuj( InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, - INTERACTION_JANK_TAG + INTERACTION_JANK_TAG, ) ) ?.let { controller -> @@ -101,7 +103,7 @@ constructor( is QSTileUserAction.LongClick -> { qsTileIntentUserActionHandler.handle( action.expandable, - Intent(Settings.ACTION_DATA_SAVER_SETTINGS) + Intent(Settings.ACTION_DATA_SAVER_SETTINGS), ) } is QSTileUserAction.ToggleClick -> {} diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt index 68fd2f5a85d4..f9b1a36621b2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModel.kt @@ -20,6 +20,10 @@ import androidx.compose.runtime.getValue import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator +import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor +import com.android.systemui.media.controls.ui.controller.MediaCarouselController +import com.android.systemui.media.controls.ui.view.MediaHost +import com.android.systemui.media.dagger.MediaModule import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel @@ -29,6 +33,7 @@ import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import javax.inject.Named import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.map @@ -41,10 +46,14 @@ constructor( shadeHeaderViewModelFactory: ShadeHeaderViewModel.Factory, tileGridViewModelFactory: TileGridViewModel.Factory, @Assisted supportsBrightnessMirroring: Boolean, + @Assisted private val expansion: Float?, val editModeViewModel: EditModeViewModel, val detailsViewModel: DetailsViewModel, - val toolbarViewModelFactory: ToolbarViewModel.Factory, + toolbarViewModelFactory: ToolbarViewModel.Factory, shadeModeInteractor: ShadeModeInteractor, + mediaCarouselInteractor: MediaCarouselInteractor, + val mediaCarouselController: MediaCarouselController, + @Named(MediaModule.QS_PANEL) val mediaHost: MediaHost, ) : ExclusiveActivatable() { private val hydrator = Hydrator("QuickSettingsContainerViewModel.hydrator") @@ -52,6 +61,8 @@ constructor( val brightnessSliderViewModel = brightnessSliderViewModelFactory.create(supportsBrightnessMirroring) + val toolbarViewModel = toolbarViewModelFactory.create() + val shadeHeaderViewModel = shadeHeaderViewModelFactory.create() val tileGridViewModel = tileGridViewModelFactory.create() @@ -63,10 +74,18 @@ constructor( source = shadeModeInteractor.isShadeLayoutWide.map { !it }, ) + val showMedia: Boolean by + hydrator.hydratedStateOf( + traceName = "showMedia", + source = mediaCarouselInteractor.hasActiveMediaOrRecommendation, + ) + override suspend fun onActivated(): Nothing { coroutineScope { + expansion?.let { mediaHost.expansion = it } launch { hydrator.activate() } launch { brightnessSliderViewModel.activate() } + launch { toolbarViewModel.activate() } launch { shadeHeaderViewModel.activate() } launch { tileGridViewModel.activate() } awaitCancellation() @@ -75,6 +94,9 @@ constructor( @AssistedFactory interface Factory { - fun create(supportsBrightnessMirroring: Boolean): QuickSettingsContainerViewModel + fun create( + supportsBrightnessMirroring: Boolean, + expansion: Float? = null, + ): QuickSettingsContainerViewModel } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt index 862dba1e7294..e775231ef2a2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt @@ -65,8 +65,7 @@ constructor( * [userDetailViewAdapterProvider] and show it as launched from [expandable]. */ fun showDialog(expandable: Expandable) { - val context = shadeDialogContextInteractor.context - with(dialogFactory.create(context)) { + with(dialogFactory.create(shadeDialogContextInteractor.context)) { setShowForAllUsers(true) setCanceledOnTouchOutside(true) diff --git a/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt b/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt new file mode 100644 index 000000000000..628280210236 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/rotationlock/DeviceStateAutoRotateModule.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.rotationlock + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController +import com.android.window.flags.Flags +import dagger.Module +import dagger.Provides +import java.util.Optional +import javax.inject.Provider +import javax.inject.Qualifier + +@Module +class DeviceStateAutoRotateModule { + /** Qualifier for dependencies to be bound with [DeviceStateAutoRotateModule]. */ + @Qualifier + @MustBeDocumented + @Retention(AnnotationRetention.RUNTIME) + annotation class BoundsDeviceStateAutoRotateModule + + /** + * Provides an instance of [DeviceStateRotationLockSettingController]. + * + * @param controllerProvider The provider for [DeviceStateRotationLockSettingController]. + * @return An [Optional] containing the [DeviceStateRotationLockSettingController] instance if + * the `Flags.enableDeviceStateAutoRotateSettingRefactor()` flag is disabled, or an empty + * [Optional] otherwise. + */ + @Provides + @BoundsDeviceStateAutoRotateModule + @SysUISingleton + fun provideDeviceStateRotationLockSettingController( + controllerProvider: Provider<DeviceStateRotationLockSettingController> + ): Optional<DeviceStateRotationLockSettingController> = + if (Flags.enableDeviceStateAutoRotateSettingRefactor()) { + Optional.empty() + } else { + Optional.of(controllerProvider.get()) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt index caa7bbae0420..e357f63479dc 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt @@ -163,4 +163,12 @@ constructor( fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) { _transitionState.value = transitionState } + + /** + * If currently in a transition between contents, cancel that transition and go back to the + * pre-transition state. + */ + fun freezeAndAnimateToCurrentState() { + dataSource.freezeAndAnimateToCurrentState() + } } diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt index a270ac5beb0f..01180859b1d2 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt @@ -234,6 +234,10 @@ constructor( * The change is animated. Therefore, it will be some time before the UI will switch to the * desired scene. Once enough of the transition has occurred, the [currentScene] will become * [toScene] (unless the transition is canceled by user action or another call to this method). + * + * If [forceSettleToTargetScene] is `true` and the target scene is the same as the current + * scene, any current transition will be canceled and an animation to the target scene will be + * started. */ @JvmOverloads fun changeScene( @@ -241,10 +245,19 @@ constructor( loggingReason: String, transitionKey: TransitionKey? = null, sceneState: Any? = null, + forceSettleToTargetScene: Boolean = false, ) { val currentSceneKey = currentScene.value val resolvedScene = sceneFamilyResolvers.get()[toScene]?.resolvedScene?.value ?: toScene + if (resolvedScene == currentSceneKey && forceSettleToTargetScene) { + logger.logSceneChangeCancellation(scene = resolvedScene, sceneState = sceneState) + onSceneAboutToChangeListener.forEach { + it.onSceneAboutToChange(resolvedScene, sceneState) + } + repository.freezeAndAnimateToCurrentState() + } + if ( !validateSceneChange( from = currentSceneKey, 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 16adf5ef976e..218ad477c45e 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 @@ -554,6 +554,7 @@ constructor( targetSceneKey = Scenes.Lockscreen, loggingReason = "device is starting to sleep", sceneState = keyguardInteractor.asleepKeyguardState.value, + freezeAndAnimateToCurrentState = true, ) } else { val canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value @@ -933,11 +934,13 @@ constructor( targetSceneKey: SceneKey, loggingReason: String, sceneState: Any? = null, + freezeAndAnimateToCurrentState: Boolean = false, ) { sceneInteractor.changeScene( toScene = targetSceneKey, loggingReason = loggingReason, sceneState = sceneState, + forceSettleToTargetScene = freezeAndAnimateToCurrentState, ) } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt index beb40ff04cc8..73c71f6088e1 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/logger/SceneLogger.kt @@ -75,6 +75,18 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: ) } + fun logSceneChangeCancellation(scene: SceneKey, sceneState: Any?) { + logBuffer.log( + tag = TAG, + level = LogLevel.INFO, + messageInitializer = { + str1 = scene.debugName + str2 = sceneState?.toString() + }, + messagePrinter = { "CANCELED scene change. scene: $str1, sceneState: $str2" }, + ) + } + fun logSceneChangeRejection( from: ContentKey?, to: ContentKey?, @@ -100,7 +112,7 @@ class SceneLogger @Inject constructor(@SceneFrameworkLog private val logBuffer: "scene " } ) - append("change because \"$str2\" ") + append("change $str1 because \"$str2\" ") append("(original change reason: \"$str3\")") } }, diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt index daf2d7f698b6..42c4b24a72d3 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSource.kt @@ -83,4 +83,10 @@ interface SceneDataSource { /** Asks for [overlay] to be instantly hidden, without an animated transition of any kind. */ fun instantlyHideOverlay(overlay: OverlayKey) + + /** + * If currently in a transition between contents, cancel that transition and go back to the + * pre-transition state. + */ + fun freezeAndAnimateToCurrentState() } diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt index dcb699539760..d6dce38d0bbf 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/SceneDataSourceDelegator.kt @@ -82,6 +82,10 @@ class SceneDataSourceDelegator(applicationScope: CoroutineScope, config: SceneCo delegateMutable.value.instantlyHideOverlay(overlay) } + override fun freezeAndAnimateToCurrentState() { + delegateMutable.value.freezeAndAnimateToCurrentState() + } + /** * Binds the current, dependency injection provided [SceneDataSource] to the given object. * @@ -120,5 +124,7 @@ class SceneDataSourceDelegator(applicationScope: CoroutineScope, config: SceneCo override fun instantlyShowOverlay(overlay: OverlayKey) = Unit override fun instantlyHideOverlay(overlay: OverlayKey) = Unit + + override fun freezeAndAnimateToCurrentState() = Unit } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index 305e71e48702..3be2f1b7b957 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -231,6 +231,9 @@ constructor( */ private var isDreaming = false + /** True if we should allow swiping open the glanceable hub. */ + private var swipeToHubEnabled = false + /** Observes and logs state when the lifecycle that controls the [touchMonitor] updates. */ private val touchLifecycleLogger: LifecycleObserver = LifecycleEventObserver { _, event -> logger.d({ @@ -438,6 +441,7 @@ constructor( }, ) collectFlow(containerView, keyguardInteractor.isDreaming, { isDreaming = it }) + collectFlow(containerView, communalViewModel.swipeToHubEnabled, { swipeToHubEnabled = it }) communalContainerWrapper = CommunalWrapper(containerView.context) communalContainerWrapper?.addView(communalContainerView) @@ -520,10 +524,7 @@ constructor( val glanceableHubV2 = communalSettingsInteractor.isV2FlagEnabled() if ( !hubShowing && - (touchOnNotifications || - touchOnUmo || - touchOnSmartspace || - !communalViewModel.swipeToHubEnabled()) + (touchOnNotifications || touchOnUmo || touchOnSmartspace || !swipeToHubEnabled) ) { logger.d({ "Lockscreen touch ignored: touchOnNotifications: $bool1, touchOnUmo: $bool2, " + diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 5746cef41d6b..131efaac3d6a 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -2201,7 +2201,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @Override @Deprecated public void onStatusBarLongPress(MotionEvent event) { - mShadeLog.d("Status Bar was long pressed."); + Log.i(TAG, "Status Bar was long pressed."); ShadeExpandsOnStatusBarLongPress.assertInNewMode(); mStatusBarLongPressDowntime = event.getDownTime(); if (isTracking()) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt index 4eb707297073..2a14ca44386d 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt @@ -20,6 +20,7 @@ import android.provider.Settings.Global.DEVELOPMENT_SHADE_DISPLAY_AWARENESS import android.view.Display import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.display.data.repository.DisplayRepository import com.android.systemui.keyguard.data.repository.KeyguardRepository import com.android.systemui.shade.ShadeOnDefaultDisplayWhenLocked import com.android.systemui.shade.display.ShadeDisplayPolicy @@ -45,7 +46,12 @@ interface ShadeDisplaysRepository { val currentPolicy: ShadeDisplayPolicy } -/** Keeps the policy and propagates the display id for the shade from it. */ +/** + * Keeps the policy and propagates the display id for the shade from it. + * + * If the display set by the policy is not available (e.g. after the cable is disconnected), this + * falls back to the [Display.DEFAULT_DISPLAY]. + */ @SysUISingleton class ShadeDisplaysRepositoryImpl @Inject @@ -56,6 +62,7 @@ constructor( policies: Set<@JvmSuppressWildcards ShadeDisplayPolicy>, @ShadeOnDefaultDisplayWhenLocked private val shadeOnDefaultDisplayWhenLocked: Boolean, keyguardRepository: KeyguardRepository, + displayRepository: DisplayRepository, ) : ShadeDisplaysRepository { private val policy: StateFlow<ShadeDisplayPolicy> = @@ -73,7 +80,12 @@ constructor( .distinctUntilChanged() .stateIn(bgScope, SharingStarted.Eagerly, defaultPolicy) - private val displayIdFromPolicy: Flow<Int> = policy.flatMapLatest { it.displayId } + private val displayIdFromPolicy: Flow<Int> = + policy + .flatMapLatest { it.displayId } + .combine(displayRepository.displayIds) { policyDisplayId, availableIds -> + if (policyDisplayId !in availableIds) Display.DEFAULT_DISPLAY else policyDisplayId + } private val keyguardAwareDisplayPolicy: Flow<Int> = if (!shadeOnDefaultDisplayWhenLocked) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt index 677e41a47afe..0002fba02be4 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/display/ShadeDisplayPolicy.kt @@ -57,7 +57,7 @@ interface ShadeExpansionIntent { @Module(includes = [AllShadeDisplayPoliciesModule::class]) interface ShadeDisplayPolicyModule { - @Binds fun provideDefaultPolicy(impl: DefaultDisplayShadePolicy): ShadeDisplayPolicy + @Binds fun provideDefaultPolicy(impl: StatusBarTouchShadeDisplayPolicy): ShadeDisplayPolicy @Binds fun provideShadeExpansionIntent(impl: StatusBarTouchShadeDisplayPolicy): ShadeExpansionIntent diff --git a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt index 1f534a5c191a..4ebdb6023268 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/display/StatusBarTouchShadeDisplayPolicy.kt @@ -26,7 +26,6 @@ import com.android.systemui.display.data.repository.DisplayRepository import com.android.systemui.shade.domain.interactor.NotificationShadeElement import com.android.systemui.shade.domain.interactor.QSShadeElement import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement -import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import dagger.Lazy import java.util.concurrent.atomic.AtomicReference @@ -53,7 +52,6 @@ class StatusBarTouchShadeDisplayPolicy constructor( displayRepository: DisplayRepository, @Background private val backgroundScope: CoroutineScope, - private val shadeInteractor: Lazy<ShadeInteractor>, private val qsShadeElement: Lazy<QSShadeElement>, private val notificationElement: Lazy<NotificationShadeElement>, ) : ShadeDisplayPolicy, ShadeExpansionIntent { diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt index 186bfcbbc8e2..a4de1d675a15 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractor.kt @@ -17,11 +17,19 @@ package com.android.systemui.shade.domain.interactor import android.content.Intent +import android.content.IntentFilter +import android.os.UserHandle import android.provider.AlarmClock +import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.plugins.ActivityStarter import com.android.systemui.shade.data.repository.ShadeHeaderClockRepository +import com.android.systemui.util.kotlin.emitOnStart +import com.android.systemui.util.time.SystemClock +import java.util.Date import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map @SysUISingleton class ShadeHeaderClockInteractor @@ -29,7 +37,20 @@ class ShadeHeaderClockInteractor constructor( private val repository: ShadeHeaderClockRepository, private val activityStarter: ActivityStarter, + private val broadcastDispatcher: BroadcastDispatcher, + private val systemClock: SystemClock, ) { + /** [Flow] that emits `Unit` whenever the timezone or locale has changed. */ + val onTimezoneOrLocaleChanged: Flow<Unit> = + broadcastFlowForActions(Intent.ACTION_TIMEZONE_CHANGED, Intent.ACTION_LOCALE_CHANGED) + .emitOnStart() + + /** [Flow] that emits the current `Date` every minute, or when the system time has changed. */ + val currentTime: Flow<Date> = + broadcastFlowForActions(Intent.ACTION_TIME_TICK, Intent.ACTION_TIME_CHANGED) + .emitOnStart() + .map { Date(systemClock.currentTimeMillis()) } + /** Launch the clock activity. */ fun launchClockActivity() { val nextAlarmIntent = repository.nextAlarmIntent @@ -38,8 +59,22 @@ constructor( } else { activityStarter.postStartActivityDismissingKeyguard( Intent(AlarmClock.ACTION_SHOW_ALARMS), - 0 + 0, ) } } + + /** + * Returns a `Flow` that, when collected, emits `Unit` whenever a broadcast matching one of the + * given [actionsToFilter] is received. + */ + private fun broadcastFlowForActions( + vararg actionsToFilter: String, + user: UserHandle = UserHandle.SYSTEM, + ): Flow<Unit> { + return broadcastDispatcher.broadcastFlow( + filter = IntentFilter().apply { actionsToFilter.forEach(::addAction) }, + user = user, + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt index 8f4e8701cad8..1ab0b93da175 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeModeInteractor.kt @@ -22,6 +22,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.scene.domain.SceneFrameworkTableLog +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository @@ -32,6 +33,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.stateIn /** @@ -89,10 +91,14 @@ constructor( ) : ShadeModeInteractor { private val isDualShadeEnabled: Flow<Boolean> = - secureSettingsRepository.boolSetting( - Settings.Secure.DUAL_SHADE, - defaultValue = DUAL_SHADE_ENABLED_DEFAULT, - ) + if (SceneContainerFlag.isEnabled) { + secureSettingsRepository.boolSetting( + Settings.Secure.DUAL_SHADE, + defaultValue = DUAL_SHADE_ENABLED_DEFAULT, + ) + } else { + flowOf(false) + } override val isShadeLayoutWide: StateFlow<Boolean> = repository.isShadeLayoutWide diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt index c23ff5302b3c..dc444ffc2a34 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt @@ -16,6 +16,7 @@ package com.android.systemui.shade.shared.flag +import android.window.DesktopExperienceFlags import com.android.systemui.Flags import com.android.systemui.flags.FlagToken import com.android.systemui.flags.RefactorFlagUtils @@ -30,10 +31,26 @@ object ShadeWindowGoesAround { val token: FlagToken get() = FlagToken(FLAG_NAME, isEnabled) + /** + * This is defined as [DesktopExperienceFlags] to make it possible to enable it together with + * all the other desktop experience flags from the dev settings. + * + * Alternatively, using adb: + * ```bash + * adb shell aflags enable com.android.window.flags.show_desktop_experience_dev_option && \ + * adb shell setprop persist.wm.debug.desktop_experience_devopts 1 + * ``` + */ + val FLAG = + DesktopExperienceFlags.DesktopExperienceFlag( + Flags::shadeWindowGoesAround, + /* shouldOverrideByDevOption= */ true, + ) + /** Is the refactor enabled */ @JvmStatic inline val isEnabled: Boolean - get() = Flags.shadeWindowGoesAround() + get() = FLAG.isTrue /** * Called to ensure code is only run when the flag is enabled. This protects users from the diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt index 8c38d2e7550c..20b44d73e097 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt @@ -18,16 +18,15 @@ package com.android.systemui.shade.ui.viewmodel import android.content.Context import android.content.Intent -import android.content.IntentFilter import android.icu.text.DateFormat import android.icu.text.DisplayContext -import android.os.UserHandle import android.provider.Settings import android.view.ViewGroup +import androidx.compose.material3.ColorScheme import androidx.compose.runtime.getValue +import androidx.compose.ui.graphics.Color import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.battery.BatteryMeterViewController -import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.plugins.ActivityStarter @@ -42,7 +41,6 @@ import com.android.systemui.shade.domain.interactor.PrivacyChipInteractor import com.android.systemui.shade.domain.interactor.ShadeHeaderClockInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeModeInteractor -import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.phone.ui.StatusBarIconController import com.android.systemui.statusbar.phone.ui.TintedIconManager @@ -50,18 +48,18 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIc import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import java.util.Date import java.util.Locale +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.mapLatest /** Models UI state for the shade header. */ +@OptIn(ExperimentalCoroutinesApi::class) class ShadeHeaderViewModel @AssistedInject constructor( @@ -70,16 +68,15 @@ constructor( private val sceneInteractor: SceneInteractor, private val shadeInteractor: ShadeInteractor, private val shadeModeInteractor: ShadeModeInteractor, - private val mobileIconsInteractor: MobileIconsInteractor, + mobileIconsInteractor: MobileIconsInteractor, val mobileIconsViewModel: MobileIconsViewModel, private val privacyChipInteractor: PrivacyChipInteractor, private val clockInteractor: ShadeHeaderClockInteractor, private val tintedIconManagerFactory: TintedIconManager.Factory, private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory, val statusBarIconController: StatusBarIconController, - val notificationIconContainerStatusBarViewBinder: NotificationIconContainerStatusBarViewBinder, - private val broadcastDispatcher: BroadcastDispatcher, ) : ExclusiveActivatable() { + private val hydrator = Hydrator("ShadeHeaderViewModel.hydrator") val createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager = @@ -127,9 +124,16 @@ constructor( /** True if there is exactly one mobile connection. */ val isSingleCarrier: StateFlow<Boolean> = mobileIconsInteractor.isSingleCarrier - private val _mobileSubIds = MutableStateFlow(emptyList<Int>()) /** The list of subscription Ids for current mobile connections. */ - val mobileSubIds: StateFlow<List<Int>> = _mobileSubIds.asStateFlow() + val mobileSubIds: List<Int> by + hydrator.hydratedStateOf( + traceName = "mobileSubIds", + initialValue = emptyList(), + source = + mobileIconsInteractor.filteredSubscriptions.map { list -> + list.map { it.subscriptionId } + }, + ) /** The list of PrivacyItems to be displayed by the privacy chip. */ val privacyItems: StateFlow<List<PrivacyItem>> = privacyChipInteractor.privacyItems @@ -150,45 +154,34 @@ constructor( private val longerPattern = context.getString(R.string.abbrev_wday_month_day_no_year_alarm) private val shorterPattern = context.getString(R.string.abbrev_month_day_no_year) - private val longerDateFormat = MutableStateFlow(getFormatFromPattern(longerPattern)) - private val shorterDateFormat = MutableStateFlow(getFormatFromPattern(shorterPattern)) - private val _shorterDateText: MutableStateFlow<String> = MutableStateFlow("") - val shorterDateText: StateFlow<String> = _shorterDateText.asStateFlow() + private val longerDateFormat: Flow<DateFormat> = + clockInteractor.onTimezoneOrLocaleChanged.mapLatest { getFormatFromPattern(longerPattern) } + private val shorterDateFormat: Flow<DateFormat> = + clockInteractor.onTimezoneOrLocaleChanged.mapLatest { getFormatFromPattern(shorterPattern) } - private val _longerDateText: MutableStateFlow<String> = MutableStateFlow("") - val longerDateText: StateFlow<String> = _longerDateText.asStateFlow() + val longerDateText: String by + hydrator.hydratedStateOf( + traceName = "longerDateText", + initialValue = "", + source = + combine(longerDateFormat, clockInteractor.currentTime) { format, time -> + format.format(time) + }, + ) + + val shorterDateText: String by + hydrator.hydratedStateOf( + traceName = "shorterDateText", + initialValue = "", + source = + combine(shorterDateFormat, clockInteractor.currentTime) { format, time -> + format.format(time) + }, + ) override suspend fun onActivated(): Nothing { coroutineScope { - launch { - broadcastDispatcher - .broadcastFlow( - filter = - IntentFilter().apply { - addAction(Intent.ACTION_TIME_TICK) - addAction(Intent.ACTION_TIME_CHANGED) - addAction(Intent.ACTION_TIMEZONE_CHANGED) - addAction(Intent.ACTION_LOCALE_CHANGED) - }, - user = UserHandle.SYSTEM, - map = { intent, _ -> - intent.action == Intent.ACTION_TIMEZONE_CHANGED || - intent.action == Intent.ACTION_LOCALE_CHANGED - }, - ) - .onEach { invalidateFormats -> updateDateTexts(invalidateFormats) } - .launchIn(this) - } - - launch { updateDateTexts(false) } - - launch { - mobileIconsInteractor.filteredSubscriptions - .map { list -> list.map { it.subscriptionId } } - .collect { _mobileSubIds.value = it } - } - launch { hydrator.activate() } awaitCancellation() @@ -253,33 +246,34 @@ constructor( /** Represents the background highlight of a header icons chip. */ sealed interface HeaderChipHighlight { - data object None : HeaderChipHighlight - data object Weak : HeaderChipHighlight + fun backgroundColor(colorScheme: ColorScheme): Color - data object Strong : HeaderChipHighlight - } + fun foregroundColor(colorScheme: ColorScheme): Color + + data object None : HeaderChipHighlight { + override fun backgroundColor(colorScheme: ColorScheme): Color = Color.Unspecified + + override fun foregroundColor(colorScheme: ColorScheme): Color = colorScheme.primary + } + + data object Weak : HeaderChipHighlight { + override fun backgroundColor(colorScheme: ColorScheme): Color = + colorScheme.primary.copy(alpha = 0.1f) - private fun updateDateTexts(invalidateFormats: Boolean) { - if (invalidateFormats) { - longerDateFormat.value = getFormatFromPattern(longerPattern) - shorterDateFormat.value = getFormatFromPattern(shorterPattern) + override fun foregroundColor(colorScheme: ColorScheme): Color = colorScheme.primary } - val currentTime = Date() + data object Strong : HeaderChipHighlight { + override fun backgroundColor(colorScheme: ColorScheme): Color = colorScheme.secondary - _longerDateText.value = longerDateFormat.value.format(currentTime) - _shorterDateText.value = shorterDateFormat.value.format(currentTime) + override fun foregroundColor(colorScheme: ColorScheme): Color = colorScheme.onSecondary + } } private fun getFormatFromPattern(pattern: String?): DateFormat { - val l = Locale.getDefault() - val format = DateFormat.getInstanceForSkeleton(pattern, l) - // The use of CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE instead of - // CAPITALIZATION_FOR_STANDALONE is to address - // https://unicode-org.atlassian.net/browse/ICU-21631 - // TODO(b/229287642): Switch back to CAPITALIZATION_FOR_STANDALONE - format.setContext(DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) + val format = DateFormat.getInstanceForSkeleton(pattern, Locale.getDefault()) + format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE) return format } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 97de61969ffb..7dc2ae71b63e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -58,7 +58,6 @@ import android.view.KeyEvent; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowInsetsController.Appearance; import android.view.WindowInsetsController.Behavior; -import android.view.accessibility.Flags; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -987,13 +986,7 @@ public class CommandQueue extends IStatusBar.Stub implements @Override public void addQsTile(ComponentName tile) { - if (Flags.a11yQsShortcut()) { - addQsTileToFrontOrEnd(tile, false); - } else { - synchronized (mLock) { - mHandler.obtainMessage(MSG_ADD_QS_TILE, tile).sendToTarget(); - } - } + addQsTileToFrontOrEnd(tile, false); } /** @@ -1003,13 +996,11 @@ public class CommandQueue extends IStatusBar.Stub implements */ @Override public void addQsTileToFrontOrEnd(ComponentName tile, boolean end) { - if (Flags.a11yQsShortcut()) { - synchronized (mLock) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = tile; - args.arg2 = end; - mHandler.obtainMessage(MSG_ADD_QS_TILE, args).sendToTarget(); - } + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = tile; + args.arg2 = end; + mHandler.obtainMessage(MSG_ADD_QS_TILE, args).sendToTarget(); } } @@ -1692,18 +1683,12 @@ public class CommandQueue extends IStatusBar.Stub implements } break; case MSG_ADD_QS_TILE: { - if (Flags.a11yQsShortcut()) { - SomeArgs someArgs = (SomeArgs) msg.obj; - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).addQsTileToFrontOrEnd( - (ComponentName) someArgs.arg1, (boolean) someArgs.arg2); - } - someArgs.recycle(); - } else { - for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).addQsTile((ComponentName) msg.obj); - } + SomeArgs someArgs = (SomeArgs) msg.obj; + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).addQsTileToFrontOrEnd( + (ComponentName) someArgs.arg1, (boolean) someArgs.arg2); } + someArgs.recycle(); break; } case MSG_REMOVE_QS_TILE: diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java index 79a872edd2c5..bfd512fa6a2d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java @@ -607,13 +607,6 @@ public final class KeyboardShortcutListSearch { context.getString(R.string.group_system_lock_screen), Arrays.asList( Pair.create(KeyEvent.KEYCODE_L, KeyEvent.META_META_ON))), - /* Pull up Notes app for quick memo: Meta + Ctrl + N */ - new ShortcutKeyGroupMultiMappingInfo( - context.getString(R.string.group_system_quick_memo), - Arrays.asList( - Pair.create( - KeyEvent.KEYCODE_N, - KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON))), /* Access system settings: Meta + I */ new ShortcutKeyGroupMultiMappingInfo( context.getString(R.string.group_system_access_system_settings), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 10f61c66c838..5b5058fbc6c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -798,6 +798,7 @@ class DragDownHelper( initialTouchY = y initialTouchX = x } + MotionEvent.ACTION_MOVE -> { val h = y - initialTouchY // Adjust the touch slop if another gesture may be being performed. @@ -852,6 +853,7 @@ class DragDownHelper( } return true } + MotionEvent.ACTION_UP -> if ( !falsingManager.isUnlockingDisabled && @@ -871,6 +873,7 @@ class DragDownHelper( stopDragging() return false } + MotionEvent.ACTION_CANCEL -> { stopDragging() return false @@ -910,7 +913,7 @@ class DragDownHelper( overshoot *= 1 - RUBBERBAND_FACTOR_STATIC rubberband -= overshoot } - child.actualHeight = (child.collapsedHeight + rubberband).toInt() + child.setFinalActualHeight((child.collapsedHeight + rubberband).toInt()) } @VisibleForTesting @@ -927,7 +930,7 @@ class DragDownHelper( anim.duration = animationDuration anim.addUpdateListener { animation: ValueAnimator -> // don't use reflection, because the `actualHeight` field may be obfuscated - child.actualHeight = animation.animatedValue as Int + child.setFinalActualHeight(animation.animatedValue as Int) } anim.addListener( object : AnimatorListenerAdapter() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java index c1b8d9d123b9..6ebe02469f5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar; +import static android.app.Flags.notificationsRedesignTemplates; + import android.app.Flags; import android.app.Notification; import android.graphics.drawable.Drawable; @@ -427,7 +429,8 @@ public class NotificationGroupingUtil { @Override public void apply(View parent, View view, boolean apply, boolean reset) { - if (reset && parent instanceof ConversationLayout) { + if (!notificationsRedesignTemplates() + && reset && parent instanceof ConversationLayout) { ConversationLayout layout = (ConversationLayout) parent; apply = layout.shouldHideAppName(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index f06565f1b6d2..32da6fff6bcc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -24,7 +24,7 @@ import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_ import static android.os.Flags.allowPrivateProfile; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_NULL; -import static android.provider.Settings.Secure.REDACT_OTP_NOTIFICATION_IMMEDIATELY; +import static android.provider.Settings.Secure.OTP_NOTIFICATION_REDACTION_LOCK_TIME; import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS; import static android.provider.Settings.Secure.REDACT_OTP_NOTIFICATION_WHILE_CONNECTED_TO_WIFI; @@ -124,10 +124,10 @@ public class NotificationLockscreenUserManagerImpl implements private static final Uri REDACT_OTP_ON_WIFI = Settings.Secure.getUriFor(REDACT_OTP_NOTIFICATION_WHILE_CONNECTED_TO_WIFI); - private static final Uri REDACT_OTP_IMMEDIATELY = - Settings.Secure.getUriFor(REDACT_OTP_NOTIFICATION_IMMEDIATELY); + private static final Uri OTP_REDACTION_LOCK_TIME = + Settings.Secure.getUriFor(OTP_NOTIFICATION_REDACTION_LOCK_TIME); - private static final long LOCK_TIME_FOR_SENSITIVE_REDACTION_MS = + private static final long DEFAULT_LOCK_TIME_FOR_SENSITIVE_REDACTION_MS = TimeUnit.MINUTES.toMillis(10); private final Lazy<NotificationVisibilityProvider> mVisibilityProviderLazy; private final Lazy<CommonNotifCollection> mCommonNotifCollectionLazy; @@ -316,7 +316,8 @@ public class NotificationLockscreenUserManagerImpl implements protected final AtomicBoolean mConnectedToWifi = new AtomicBoolean(false); protected final AtomicBoolean mRedactOtpOnWifi = new AtomicBoolean(true); - protected final AtomicBoolean mRedactOtpImmediately = new AtomicBoolean(false); + protected final AtomicLong mOtpRedactionRequiredLockTimeMs = + new AtomicLong(DEFAULT_LOCK_TIME_FOR_SENSITIVE_REDACTION_MS); protected int mCurrentUserId = 0; @@ -375,7 +376,7 @@ public class NotificationLockscreenUserManagerImpl implements mLockScreenUris.add(SHOW_LOCKSCREEN); mLockScreenUris.add(SHOW_PRIVATE_LOCKSCREEN); mLockScreenUris.add(REDACT_OTP_ON_WIFI); - mLockScreenUris.add(REDACT_OTP_IMMEDIATELY); + mLockScreenUris.add(OTP_REDACTION_LOCK_TIME); dumpManager.registerDumpable(this); @@ -447,8 +448,8 @@ public class NotificationLockscreenUserManagerImpl implements changed |= updateUserShowPrivateSettings(user.getIdentifier()); } else if (REDACT_OTP_ON_WIFI.equals(uri)) { changed |= updateRedactOtpOnWifiSetting(); - } else if (REDACT_OTP_IMMEDIATELY.equals(uri)) { - changed |= updateRedactOtpImmediatelySetting(); + } else if (OTP_REDACTION_LOCK_TIME.equals(uri)) { + changed |= updateOtpLockTimeSetting(); } } @@ -487,7 +488,7 @@ public class NotificationLockscreenUserManagerImpl implements mLockscreenSettingsObserver ); mSecureSettings.registerContentObserverAsync( - REDACT_OTP_IMMEDIATELY, + OTP_REDACTION_LOCK_TIME, mLockscreenSettingsObserver ); @@ -638,13 +639,13 @@ public class NotificationLockscreenUserManagerImpl implements } @WorkerThread - private boolean updateRedactOtpImmediatelySetting() { - boolean originalValue = mRedactOtpImmediately.get(); - boolean newValue = mSecureSettings.getIntForUser( - REDACT_OTP_NOTIFICATION_IMMEDIATELY, - 0, - Process.myUserHandle().getIdentifier()) != 0; - mRedactOtpImmediately.set(newValue); + private boolean updateOtpLockTimeSetting() { + long originalValue = mOtpRedactionRequiredLockTimeMs.get(); + long newValue = mSecureSettings.getLongForUser( + OTP_NOTIFICATION_REDACTION_LOCK_TIME, + DEFAULT_LOCK_TIME_FOR_SENSITIVE_REDACTION_MS, + Process.myUserHandle().getIdentifier()); + mOtpRedactionRequiredLockTimeMs.set(newValue); return originalValue != newValue; } @@ -832,14 +833,9 @@ public class NotificationLockscreenUserManagerImpl implements return false; } - long latestTimeForRedaction; - if (mRedactOtpImmediately.get()) { - latestTimeForRedaction = mLastLockTime.get(); - } else { - // If the lock screen was not already locked for LOCK_TIME_FOR_SENSITIVE_REDACTION_MS - // when this notification arrived, do not redact - latestTimeForRedaction = mLastLockTime.get() + LOCK_TIME_FOR_SENSITIVE_REDACTION_MS; - } + // If the lock screen was not already locked for at least mOtpRedactionRequiredLockTimeMs + // when this notification arrived, do not redact + long latestTimeForRedaction = mLastLockTime.get() + mOtpRedactionRequiredLockTimeMs.get(); if (ent.getSbn().getPostTime() < latestTimeForRedaction) { return false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt index 85b8bf9aec80..3be7682fe250 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt @@ -140,8 +140,8 @@ constructor( private fun canHandleMotionEvent(): Boolean { return wakeUpCoordinator.canShowPulsingHuns && - !shadeInteractor.isQsExpanded.value && - !bouncerShowing + !shadeInteractor.isQsExpanded.value && + !bouncerShowing } private fun startExpansion(event: MotionEvent): Boolean { @@ -194,7 +194,7 @@ constructor( override fun onTouchEvent(event: MotionEvent): Boolean { val finishExpanding = (event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_UP) && - isExpanding + isExpanding val isDraggingNotificationOrCanBypass = mStartingChild?.showingPulsing() == true || bypassController.canBypass() @@ -218,8 +218,8 @@ constructor( velocityTracker!!.computeCurrentVelocity(/* units= */ 1000) val canExpand = moveDistance > 0 && - velocityTracker!!.getYVelocity() > -1000 && - statusBarStateController.state != StatusBarState.SHADE + velocityTracker!!.getYVelocity() > -1000 && + statusBarStateController.state != StatusBarState.SHADE if (!falsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) { finishExpansion() } else { @@ -266,11 +266,11 @@ constructor( val child = mStartingChild!! val newHeight = Math.min((child.collapsedHeight + expansionHeight).toInt(), child.maxContentHeight) - child.actualHeight = newHeight + child.setFinalActualHeight(newHeight) } else { wakeUpCoordinator.setNotificationsVisibleForExpansion( height > - lockscreenShadeTransitionController.distanceUntilShowingPulsingNotifications, + lockscreenShadeTransitionController.distanceUntilShowingPulsingNotifications, /*animate= */ true, /*increaseSpeed= */ true, ) @@ -301,7 +301,7 @@ constructor( anim.duration = animationDuration anim.addUpdateListener { animation: ValueAnimator -> // don't use reflection, because the `actualHeight` field may be obfuscated - child.actualHeight = animation.animatedValue as Int + child.setFinalActualHeight(animation.animatedValue as Int) } anim.addListener( object : AnimatorListenerAdapter() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt index d20a2d18a7e7..edb44185459c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt @@ -145,7 +145,7 @@ constructor( * Emits all notifications that are eligible to show as chips in the status bar. This is * different from which chips will *actually* show, see [shownNotificationChips] for that. */ - private val allNotificationChips: Flow<List<NotificationChipModel>> = + val allNotificationChips: Flow<List<NotificationChipModel>> = if (StatusBarNotifChips.isEnabled) { // For all our current interactors... // TODO(b/364653005): When a promoted notification is added or removed, each individual diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt index 3ecbdf82f2cb..994357f909e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.notification.domain.model.TopPinnedState import com.android.systemui.statusbar.notification.headsup.PinnedStatus import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization +import com.android.systemui.util.time.SystemClock import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow @@ -51,6 +52,7 @@ constructor( @Application private val applicationScope: CoroutineScope, private val notifChipsInteractor: StatusBarNotificationChipsInteractor, headsUpNotificationInteractor: HeadsUpNotificationInteractor, + private val systemClock: SystemClock, ) { /** * A flow modeling the notification chips that should be shown. Emits an empty list if there are @@ -158,34 +160,46 @@ constructor( clickBehavior, ) } - when (this.promotedContent.time.mode) { - PromotedNotificationContentModel.When.Mode.BasicTime -> { - return OngoingActivityChipModel.Active.ShortTimeDelta( - this.key, - icon, - colors, - time = this.promotedContent.time.time, - onClickListenerLegacy, - clickBehavior, - ) - } - PromotedNotificationContentModel.When.Mode.CountUp -> { - return OngoingActivityChipModel.Active.Timer( - this.key, - icon, - colors, - startTimeMs = this.promotedContent.time.time, - onClickListenerLegacy, - clickBehavior, - ) + + when (this.promotedContent.time) { + is PromotedNotificationContentModel.When.Time -> { + return if ( + this.promotedContent.time.currentTimeMillis >= + systemClock.currentTimeMillis() + FUTURE_TIME_THRESHOLD_MILLIS + ) { + OngoingActivityChipModel.Active.ShortTimeDelta( + this.key, + icon, + colors, + time = this.promotedContent.time.currentTimeMillis, + onClickListenerLegacy, + clickBehavior, + ) + } else { + // Don't show a `when` time that's close to now or in the past because it's + // likely that the app didn't intentionally set the `when` time to be shown in + // the status bar chip. + // TODO(b/393369213): If a notification sets a `when` time in the future and + // then that time comes and goes, the chip *will* start showing times in the + // past. Not going to fix this right now because the Compose implementation + // automatically handles this for us and we're hoping to launch the notification + // chips at the same time as the Compose chips. + return OngoingActivityChipModel.Active.IconOnly( + this.key, + icon, + colors, + onClickListenerLegacy, + clickBehavior, + ) + } } - PromotedNotificationContentModel.When.Mode.CountDown -> { - // TODO(b/364653005): Support CountDown. + is PromotedNotificationContentModel.When.Chronometer -> { + // TODO(b/364653005): Check isCountDown and support CountDown. return OngoingActivityChipModel.Active.Timer( this.key, icon, colors, - startTimeMs = this.promotedContent.time.time, + startTimeMs = this.promotedContent.time.elapsedRealtimeMillis, onClickListenerLegacy, clickBehavior, ) @@ -204,4 +218,12 @@ constructor( ) ) } + + companion object { + /** + * Notifications must have a `when` time of at least 1 minute in the future in order for the + * status bar chip to show the time. + */ + private const val FUTURE_TIME_THRESHOLD_MILLIS = 60 * 1000 + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt index d41353b2c176..20dec11577df 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt @@ -408,11 +408,13 @@ object OngoingActivityChipBinder { private fun View.setBackgroundPaddingForEmbeddedPaddingIcon() { val sidePadding = if (StatusBarNotifChips.isEnabled) { - 0 - } else { context.resources.getDimensionPixelSize( R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon ) + } else { + context.resources.getDimensionPixelSize( + R.dimen.ongoing_activity_chip_side_padding_for_embedded_padding_icon_legacy + ) } setPaddingRelative(sidePadding, paddingTop, sidePadding, paddingBottom) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt index 4a999d5f5e0e..efd402ead979 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import com.android.compose.animation.Expandable import com.android.compose.modifiers.thenIf @@ -160,7 +159,10 @@ private fun ChipBody( .padding( horizontal = if (hasEmbeddedIcon) { - 0.dp + dimensionResource( + R.dimen + .ongoing_activity_chip_side_padding_for_embedded_padding_icon + ) } else { dimensionResource(id = R.dimen.ongoing_activity_chip_side_padding) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt index 4017c436151e..3b8c0f48e40e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt @@ -24,7 +24,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.key import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import androidx.compose.ui.res.dimensionResource +import com.android.systemui.res.R import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder @@ -35,10 +36,13 @@ fun OngoingActivityChips( modifier: Modifier = Modifier, ) { Row( - // TODO(b/372657935): Remove magic numbers for padding and spacing. - modifier = modifier.fillMaxHeight().padding(horizontal = 6.dp), + modifier = + modifier + .fillMaxHeight() + .padding(start = dimensionResource(R.dimen.ongoing_activity_chip_margin_start)), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = + Arrangement.spacedBy(dimensionResource(R.dimen.ongoing_activity_chip_margin_start)), ) { chips.active .filter { !it.isHidden } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt index 6cb8a5328732..cf0342b89c00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt @@ -128,7 +128,10 @@ sealed class OngoingActivityChipModel { override val key: String, override val icon: ChipIcon, override val colors: ColorsModel, - /** The time of the event that this chip represents. */ + /** + * The time of the event that this chip represents, relative to + * [com.android.systemui.util.time.SystemClock.currentTimeMillis]. + */ val time: Long, override val onClickListenerLegacy: View.OnClickListener?, override val clickBehavior: ClickBehavior, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java index dbcda418496e..cfc0055954b9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java @@ -32,12 +32,16 @@ public class WifiIcons { */ private static int[] getIconsBasedOnFlag() { if (newStatusBarIcons()) { + // TODO(b/396664075): + // The new wifi icons only define a range of [0, 3]. Since this array is indexed on + // level, we can simulate the range squash by mapping both level 3 to drawn-level 2, and + // level 4 to drawn-level 3 return new int[] { R.drawable.ic_wifi_0, R.drawable.ic_wifi_1, R.drawable.ic_wifi_2, - R.drawable.ic_wifi_3, - R.drawable.ic_wifi_4 + R.drawable.ic_wifi_2, + R.drawable.ic_wifi_3 }; } else { return new int[] { @@ -54,12 +58,13 @@ public class WifiIcons { private static int [] getErrorIconsBasedOnFlag() { if (newStatusBarIcons()) { + // See above note, new wifi icons only have 3 bars, so levels 2 and 3 are the same return new int[] { R.drawable.ic_wifi_0_error, R.drawable.ic_wifi_1_error, R.drawable.ic_wifi_2_error, + R.drawable.ic_wifi_2_error, R.drawable.ic_wifi_3_error, - R.drawable.ic_wifi_4_error }; } else { return new int[] { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt index e3be95373698..402881d438dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt @@ -29,10 +29,10 @@ object NewStatusBarIcons { val token: FlagToken get() = FlagToken(FLAG_NAME, isEnabled) - /** Is the refactor enabled */ + /** Is the refactor enabled. Dependency on [StatusBarRootModernization] */ @JvmStatic inline val isEnabled - get() = Flags.newStatusBarIcons() + get() = Flags.newStatusBarIcons() && StatusBarRootModernization.isEnabled /** * Called to ensure code is only run when the flag is enabled. This protects users from the diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt index 7f0f6078f391..90f97df295f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt @@ -82,10 +82,6 @@ constructor( chipId = PopupChipId.MediaControl, icon = defaultIcon, chipText = model.songName.toString(), - isToggled = false, - // TODO(b/385202114): Show a popup containing the media carousal when the chip is - // toggled. - onToggle = {}, hoverBehavior = createHoverBehavior(model), ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt index 683b97166f3e..60615536ab67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/shared/model/PopupChipModel.kt @@ -53,10 +53,11 @@ sealed class PopupChipModel { /** Default icon displayed on the chip */ val icon: Icon, val chipText: String, - val isToggled: Boolean = false, - val onToggle: () -> Unit, + val isPopupShown: Boolean = false, + val showPopup: () -> Unit = {}, + val hidePopup: () -> Unit = {}, val hoverBehavior: HoverBehavior = HoverBehavior.None, ) : PopupChipModel() { - override val logName = "Shown(id=$chipId, toggled=$isToggled)" + override val logName = "Shown(id=$chipId, toggled=$isPopupShown)" } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt new file mode 100644 index 000000000000..8a66904ea59b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopup.kt @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.featurepods.popups.ui.compose + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Popup +import androidx.compose.ui.window.PopupProperties +import com.android.systemui.res.R +import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId +import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel + +/** + * Displays a popup in the status bar area. The offset is calculated to draw the popup below the + * status bar. + */ +@Composable +fun StatusBarPopup(viewModel: PopupChipModel.Shown) { + val density = Density(LocalContext.current) + Popup( + properties = + PopupProperties( + focusable = false, + dismissOnBackPress = true, + dismissOnClickOutside = true, + ), + offset = + IntOffset( + x = 0, + y = with(density) { dimensionResource(R.dimen.status_bar_height).roundToPx() }, + ), + onDismissRequest = { viewModel.hidePopup() }, + ) { + Box(modifier = Modifier.padding(8.dp).wrapContentSize()) { + when (viewModel.chipId) { + is PopupChipId.MediaControl -> { + // TODO(b/385202114): Populate MediaControlPopup contents. + } + } + // Future popup types will be handled here. + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt index 34bef9d3ca3a..eb85d2f32f29 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChip.kt @@ -52,14 +52,14 @@ import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipM * the chip can show text containing contextual information. */ @Composable -fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifier) { - val hasHoverBehavior = model.hoverBehavior !is HoverBehavior.None +fun StatusBarPopupChip(viewModel: PopupChipModel.Shown, modifier: Modifier = Modifier) { + val hasHoverBehavior = viewModel.hoverBehavior !is HoverBehavior.None val hoverInteractionSource = remember { MutableInteractionSource() } val isHovered by hoverInteractionSource.collectIsHoveredAsState() - val isToggled = model.isToggled + val isPopupShown = viewModel.isPopupShown val chipBackgroundColor = - if (isToggled) { + if (isPopupShown) { MaterialTheme.colorScheme.primaryContainer } else { MaterialTheme.colorScheme.surfaceContainerHighest @@ -72,7 +72,7 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie .padding(vertical = 4.dp) .animateContentSize() .thenIf(hasHoverBehavior) { Modifier.hoverable(hoverInteractionSource) } - .clickable { model.onToggle() }, + .thenIf(!isPopupShown) { Modifier.clickable { viewModel.showPopup() } }, color = chipBackgroundColor, ) { Row( @@ -82,14 +82,14 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie ) { val iconColor = if (isHovered) chipBackgroundColor else contentColorFor(chipBackgroundColor) - val hoverBehavior = model.hoverBehavior + val hoverBehavior = viewModel.hoverBehavior val iconBackgroundColor = contentColorFor(chipBackgroundColor) val iconInteractionSource = remember { MutableInteractionSource() } Icon( icon = when { isHovered && hoverBehavior is HoverBehavior.Button -> hoverBehavior.icon - else -> model.icon + else -> viewModel.icon }, modifier = Modifier.thenIf(isHovered) { @@ -109,7 +109,7 @@ fun StatusBarPopupChip(model: PopupChipModel.Shown, modifier: Modifier = Modifie ) Text( - text = model.chipText, + text = viewModel.chipText, style = MaterialTheme.typography.labelLarge, softWrap = false, overflow = TextOverflow.Ellipsis, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt index d35674d8dd9f..16538c93cf35 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/compose/StatusBarPopupChipsContainer.kt @@ -31,10 +31,15 @@ fun StatusBarPopupChipsContainer(chips: List<PopupChipModel.Shown>, modifier: Mo // TODO(b/385353140): Add padding and spacing for this container according to UX specs. Box { Row( - modifier = Modifier.padding(horizontal = 8.dp), + modifier = modifier.padding(horizontal = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { - chips.forEach { chip -> StatusBarPopupChip(chip) } + chips.forEach { chip -> + StatusBarPopupChip(chip) + if (chip.isPopupShown) { + StatusBarPopup(chip) + } + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt index caa8e6cc02c3..33bf90defb48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt @@ -16,49 +16,65 @@ package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Background +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.lifecycle.Hydrator import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.MediaControlChipViewModel import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel -import javax.inject.Inject -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn /** * View model deciding which system process chips to show in the status bar. Emits a list of * PopupChipModels. */ -@SysUISingleton class StatusBarPopupChipsViewModel -@Inject -constructor( - @Background scope: CoroutineScope, - mediaControlChipViewModel: MediaControlChipViewModel, -) { - private data class PopupChipBundle( - val media: PopupChipModel = PopupChipModel.Hidden(chipId = PopupChipId.MediaControl) - ) +@AssistedInject +constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable() { + private val hydrator: Hydrator = Hydrator("StatusBarPopupChipsViewModel.hydrator") - private val incomingPopupChipBundle: StateFlow<PopupChipBundle?> = - mediaControlChipViewModel.chip - .map { chip -> PopupChipBundle(media = chip) } - .stateIn(scope, SharingStarted.WhileSubscribed(), PopupChipBundle()) + /** The ID of the current chip that is showing its popup, or `null` if no chip is shown. */ + private var currentShownPopupChipId by mutableStateOf<PopupChipId?>(null) - val shownPopupChips: StateFlow<List<PopupChipModel.Shown>> = + private val incomingPopupChipBundle: PopupChipBundle by + hydrator.hydratedStateOf( + traceName = "incomingPopupChipBundle", + initialValue = PopupChipBundle(), + source = mediaControlChip.chip.map { chip -> PopupChipBundle(media = chip) }, + ) + + val shownPopupChips: List<PopupChipModel.Shown> by derivedStateOf { if (StatusBarPopupChips.isEnabled) { - incomingPopupChipBundle - .map { bundle -> - listOfNotNull(bundle?.media).filterIsInstance<PopupChipModel.Shown>() - } - .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList()) + val bundle = incomingPopupChipBundle + + listOfNotNull(bundle.media).filterIsInstance<PopupChipModel.Shown>().map { chip -> + chip.copy( + isPopupShown = chip.chipId == currentShownPopupChipId, + showPopup = { currentShownPopupChipId = chip.chipId }, + hidePopup = { currentShownPopupChipId = null }, + ) + } } else { - MutableStateFlow(emptyList<PopupChipModel.Shown>()).asStateFlow() + emptyList() } + } + + override suspend fun onActivated(): Nothing { + hydrator.activate() + } + + private data class PopupChipBundle( + val media: PopupChipModel = PopupChipModel.Hidden(chipId = PopupChipId.MediaControl) + ) + + @AssistedFactory + interface Factory { + fun create(): StatusBarPopupChipsViewModel + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt index 7b5f5f6d8060..e6dd09b1e1b2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt @@ -97,7 +97,7 @@ constructor( private val secureSettings: SecureSettings, private val userTracker: UserTracker, private val contentResolver: ContentResolver, - private val configurationController: ConfigurationController, + @ShadeDisplayAware private val configurationController: ConfigurationController, private val statusBarStateController: StatusBarStateController, private val deviceProvisionedController: DeviceProvisionedController, private val bypassController: KeyguardBypassController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java index eb1be6772b99..c6775d6dc051 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java @@ -24,6 +24,7 @@ import android.widget.ImageView; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.res.R; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.util.Compile; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt new file mode 100644 index 000000000000..74faf2576abd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.systemui.statusbar.notification + +import android.util.Property +import android.view.View +import androidx.dynamicanimation.animation.DynamicAnimation +import androidx.dynamicanimation.animation.FloatPropertyCompat +import androidx.dynamicanimation.animation.SpringAnimation +import androidx.dynamicanimation.animation.SpringForce +import com.android.systemui.res.R +import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.Companion.createDefaultSpring +import com.android.systemui.statusbar.notification.stack.AnimationProperties + +/** + * A physically animatable property of a view. + * + * @param tag the view tag to safe this property in + * @param property the property to animate. + */ +data class PhysicsProperty(val tag: Int, val property: Property<View, Float>) { + val offsetProperty = + object : FloatPropertyCompat<View>(property.name) { + override fun getValue(view: View): Float { + return property.get(view) + } + + override fun setValue(view: View, offset: Float) { + val propertyData = view.getTag(tag) as PropertyData? ?: return + propertyData.offset = offset + property.set(view, propertyData.finalValue + offset) + } + } + + fun setFinalValue(view: View, finalValue: Float) { + val propertyData = obtainPropertyData(view, this) + val previousValue = propertyData.finalValue + if (previousValue != finalValue) { + propertyData.finalValue = finalValue + property.set(view, propertyData.finalValue + propertyData.offset) + } + } +} + +/** The propertyData associated with each animation running */ +data class PropertyData( + var finalValue: Float = 0f, + var offset: Float = 0f, + var animator: SpringAnimation? = null, + var delayRunnable: Runnable? = null, +) + +/** + * A utility that can run physics based animations in a simple way. It properly handles overlapping + * calls where sometimes a property can be set without animation, while also having instances where + * it's supposed to start animations. + * + * This overall helps making sure that physics based animations complete and don't constantly start + * new transitions which can lead to a feeling of lagging behind. + * + * Overall it is achieved by starting offset animations to an end value as soon as an animation is + * requested and updating the end value immediately when no animation is needed. With the offset + * always going to 0, this ensures that animations complete within a short time after an animation + * has been requested. + */ +class PhysicsPropertyAnimator { + companion object { + @JvmField val TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag + + @JvmField + val Y_TRANSLATION: PhysicsProperty = + PhysicsProperty(TAG_ANIMATOR_TRANSLATION_Y, View.TRANSLATION_Y) + + // Uses the standard spatial material spring by default + @JvmStatic + fun createDefaultSpring(): SpringForce { + return SpringForce() + .setStiffness(380f) // MEDIUM LOW STIFFNESS + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) // LOW BOUNCINESS + } + + @JvmStatic + @JvmOverloads + /** + * Set a property on a view, updating its value, even if it's already animating. The @param + * animated can be used to request an animation. If the view isn't animated, this utility + * will update the current animation if existent, such that the end value will point + * to @param newEndValue or apply it directly if there's no animation. + */ + fun setProperty( + view: View, + animatableProperty: PhysicsProperty, + newEndValue: Float, + properties: AnimationProperties? = null, + animated: Boolean = false, + endListener: DynamicAnimation.OnAnimationEndListener? = null, + ) { + if (animated) { + startAnimation(view, animatableProperty, newEndValue, properties, endListener) + } else { + animatableProperty.setFinalValue(view, newEndValue) + } + } + + fun isAnimating(view: View, property: PhysicsProperty): Boolean { + val (_, _, animator, _) = obtainPropertyData(view, property) + return animator?.isRunning ?: false + } + } +} + +private fun startAnimation( + view: View, + animatableProperty: PhysicsProperty, + newEndValue: Float, + properties: AnimationProperties?, + endListener: DynamicAnimation.OnAnimationEndListener?, +) { + val property = animatableProperty.property + val propertyData = obtainPropertyData(view, animatableProperty) + val previousEndValue = propertyData.finalValue + if (previousEndValue == newEndValue) { + return + } + propertyData.finalValue = newEndValue + var animator = propertyData.animator + if (animator == null) { + animator = SpringAnimation(view, animatableProperty.offsetProperty) + propertyData.animator = animator + animator.setSpring(createDefaultSpring()) + val listener = properties?.getAnimationEndListener(animatableProperty.property) + if (listener != null) { + animator.addEndListener(listener) + // We always notify things as started even if we have a delay + properties.getAnimationStartListener(animatableProperty.property)?.accept(animator) + } + // remove the tag when the animation is finished + animator.addEndListener { _, _, _, _ -> propertyData.animator = null } + } + // TODO(b/393581344): look at custom spring + endListener?.let { animator.addEndListener(it) } + val newOffset = previousEndValue - newEndValue + propertyData.offset + + // Immedialely set the new offset that compensates for the immediate end value change + propertyData.offset = newOffset + property.set(view, newEndValue + newOffset) + + // cancel previous starters still pending + view.removeCallbacks(propertyData.delayRunnable) + animator.setStartValue(newOffset) + val startRunnable = Runnable { + animator.animateToFinalPosition(0f) + propertyData.delayRunnable = null + } + if (properties != null && properties.delay > 0 && !animator.isRunning) { + propertyData.delayRunnable = startRunnable + view.postDelayed(propertyData.delayRunnable, properties.delay) + } else { + startRunnable.run() + } +} + +private fun obtainPropertyData(view: View, animatableProperty: PhysicsProperty): PropertyData { + var propertyData = view.getTag(animatableProperty.tag) as PropertyData? + if (propertyData == null) { + propertyData = + PropertyData(finalValue = animatableProperty.property.get(view), offset = 0f, null) + view.setTag(animatableProperty.tag, propertyData) + } + return propertyData +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java index 37485feed792..24ab6959b9e1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java @@ -16,11 +16,116 @@ package com.android.systemui.statusbar.notification.collection; +import static android.app.NotificationChannel.NEWS_ID; +import static android.app.NotificationChannel.PROMOTIONS_ID; +import static android.app.NotificationChannel.RECS_ID; +import static android.app.NotificationChannel.SOCIAL_MEDIA_ID; + +import android.app.Notification; +import android.content.Context; +import android.os.Build; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.systemui.statusbar.notification.icon.IconPack; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; + +import java.util.List; + /** * Abstract class to represent notification section bundled by AI. */ public class BundleEntry extends PipelineEntry { + private final String mKey; + private final BundleEntryAdapter mEntryAdapter; + + // TODO (b/389839319): implement the row + private ExpandableNotificationRow mRow; + + public BundleEntry(String key) { + mKey = key; + mEntryAdapter = new BundleEntryAdapter(); + } + + @VisibleForTesting + public BundleEntryAdapter getEntryAdapter() { + return mEntryAdapter; + } + public class BundleEntryAdapter implements EntryAdapter { + + /** + * TODO (b/394483200): convert to PipelineEntry.ROOT_ENTRY when pipeline is migrated? + */ + @Override + public GroupEntry getParent() { + return GroupEntry.ROOT_ENTRY; + } + + @Override + public boolean isTopLevelEntry() { + return true; + } + + @Override + public String getKey() { + return mKey; + } + + @Override + public ExpandableNotificationRow getRow() { + return mRow; + } + + @Nullable + @Override + public EntryAdapter getGroupRoot() { + return this; + } + + @Override + public boolean isClearable() { + // TODO(b/394483200): check whether all of the children are clearable, when implemented + return true; + } + + @Override + public int getTargetSdk() { + return Build.VERSION_CODES.CUR_DEVELOPMENT; + } + + @Override + public String getSummarization() { + return null; + } + + @Override + public int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor) { + return Notification.COLOR_DEFAULT; + } + + @Override + public boolean canPeek() { + return false; + } + + @Override + public long getWhen() { + return 0; + } + + @Override + public IconPack getIcons() { + // TODO(b/396446620): implement bundle icons + return null; + } } + + public static final List<BundleEntry> ROOT_BUNDLES = List.of( + new BundleEntry(PROMOTIONS_ID), + new BundleEntry(SOCIAL_MEDIA_ID), + new BundleEntry(NEWS_ID), + new BundleEntry(RECS_ID)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java index b12b1c538a32..6431cacf2107 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java @@ -16,8 +16,95 @@ package com.android.systemui.statusbar.notification.collection; +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.systemui.statusbar.notification.icon.IconPack; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; + /** * Adapter interface for UI to get relevant info. */ public interface EntryAdapter { + + /** + * Gets the parent of this entry, or null if the entry's view is not attached + */ + @Nullable PipelineEntry getParent(); + + /** + * Returns whether the entry is attached and appears at the top level of the shade + */ + boolean isTopLevelEntry(); + + /** + * @return the unique identifier for this entry + */ + @NonNull String getKey(); + + /** + * Gets the view that this entry is backing. + */ + @NonNull + ExpandableNotificationRow getRow(); + + /** + * Gets the EntryAdapter that is the nearest root of the collection of rows the given entry + * belongs to. If the given entry is a BundleEntry or an isolated child of a BundleEntry, the + * BundleEntry will be returned. If the given notification is a group summary NotificationEntry, + * or a child of a group summary, the summary NotificationEntry will be returned, even if that + * summary belongs to a BundleEntry. If the entry is a notification that does not belong to any + * group or bundle grouping, null will be returned. + */ + @Nullable + EntryAdapter getGroupRoot(); + + /** + * @return whether the row can be removed with the 'Clear All' action + */ + boolean isClearable(); + + /** + * Returns whether the entry is attached to the current shade list + */ + default boolean isAttached() { + return getParent() != null; + } + + /** + * Returns the target sdk of the package that owns this entry. + */ + int getTargetSdk(); + + /** + * Returns the summarization for this entry, if there is one + */ + @Nullable String getSummarization(); + + /** + * Performs any steps needed to set or reset data before an inflation or reinflation. + */ + default void prepareForInflation() {} + + /** + * Gets a color that would have sufficient contrast on the given background color. + */ + int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor); + + /** + * Whether this entry can peek on screen as a heads up view + */ + boolean canPeek(); + + /** + * Returns the visible 'time', in milliseconds, of the entry + */ + long getWhen(); + + /** + * Retrieves the pack of icons associated with this entry + */ + IconPack getIcons(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java index fc47dc1ed81a..8f3c357a277a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java @@ -24,6 +24,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.NotifInf import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import javax.inject.Inject; @@ -78,7 +79,7 @@ public class NotifInflaterImpl implements NotifInflater { requireBinder().inflateViews( entry, params, - wrapInflationCallback(callback)); + wrapInflationCallback(entry, callback)); } catch (InflationException e) { mLogger.logInflationException(entry, e); mNotifErrorManager.setInflationError(entry, e); @@ -101,17 +102,26 @@ public class NotifInflaterImpl implements NotifInflater { } private NotificationRowContentBinder.InflationCallback wrapInflationCallback( + final NotificationEntry entry, InflationCallback callback) { return new NotificationRowContentBinder.InflationCallback() { @Override public void handleInflationException( NotificationEntry entry, Exception e) { + if (NotificationBundleUi.isEnabled()) { + handleInflationException(e); + } else { + mNotifErrorManager.setInflationError(entry, e); + } + } + @Override + public void handleInflationException(Exception e) { mNotifErrorManager.setInflationError(entry, e); } @Override - public void onAsyncInflationFinished(NotificationEntry entry) { + public void onAsyncInflationFinished() { mNotifErrorManager.clearInflationError(entry); if (callback != null) { callback.onInflationFinished(entry, entry.getRowController()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 7dd82a6b5198..698a56363465 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -29,6 +29,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICAT import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import static com.android.systemui.statusbar.notification.collection.BundleEntry.ROOT_BUNDLES; +import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY; import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING; @@ -76,6 +78,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGuts; import com.android.systemui.statusbar.notification.row.shared.HeadsUpStatusBarModel; import com.android.systemui.statusbar.notification.row.shared.NotificationContentModel; import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.stack.PriorityBucket; import com.android.systemui.util.ListenerSet; @@ -107,6 +110,7 @@ public final class NotificationEntry extends ListEntry { private final String mKey; private StatusBarNotification mSbn; private Ranking mRanking; + private final NotifEntryAdapter mEntryAdapter; /* * Bookkeeping members @@ -268,9 +272,89 @@ public final class NotificationEntry extends ListEntry { mKey = sbn.getKey(); setSbn(sbn); setRanking(ranking); + mEntryAdapter = new NotifEntryAdapter(); } public class NotifEntryAdapter implements EntryAdapter { + @Override + public PipelineEntry getParent() { + return NotificationEntry.this.getParent(); + } + + @Override + public boolean isTopLevelEntry() { + return getParent() != null + && (getParent() == ROOT_ENTRY || ROOT_BUNDLES.contains(getParent())); + } + + @Override + public String getKey() { + return NotificationEntry.this.getKey(); + } + + @Override + public ExpandableNotificationRow getRow() { + return NotificationEntry.this.getRow(); + } + + @Nullable + @Override + public EntryAdapter getGroupRoot() { + // TODO (b/395857098): for backwards compatibility this will return null if called + // on a group summary that's not in a bundles, but it should return itself. + if (isTopLevelEntry() || getParent() == null) { + return null; + } + if (NotificationEntry.this.getParent().getSummary() != null) { + return NotificationEntry.this.getParent().getSummary().mEntryAdapter; + } + return null; + } + + @Override + public boolean isClearable() { + return NotificationEntry.this.isClearable(); + } + + @Override + public int getTargetSdk() { + return NotificationEntry.this.targetSdk; + } + + @Override + public String getSummarization() { + return getRanking().getSummarization(); + } + + @Override + public void prepareForInflation() { + getSbn().clearPackageContext(); + } + + @Override + public int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor) { + return NotificationEntry.this.getContrastedColor( + context, isLowPriority, backgroundColor); + } + + @Override + public boolean canPeek() { + return isStickyAndNotDemoted(); + } + + @Override + public long getWhen() { + return getSbn().getNotification().getWhen(); + } + + @Override + public IconPack getIcons() { + return NotificationEntry.this.getIcons(); + } + } + + public EntryAdapter getEntryAdapter() { + return mEntryAdapter; } @Override @@ -538,6 +622,7 @@ public final class NotificationEntry extends ListEntry { } public boolean hasFinishedInitialization() { + NotificationBundleUi.assertInLegacyMode(); return initializationTime != -1 && SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY; } @@ -621,10 +706,12 @@ public final class NotificationEntry extends ListEntry { } public void resetInitializationTime() { + NotificationBundleUi.assertInLegacyMode(); initializationTime = -1; } public void setInitializationTime(long time) { + NotificationBundleUi.assertInLegacyMode(); if (initializationTime == -1) { initializationTime = time; } @@ -641,9 +728,13 @@ public final class NotificationEntry extends ListEntry { * @return {@code true} if we are a media notification */ public boolean isMediaNotification() { - if (row == null) return false; + if (NotificationBundleUi.isEnabled()) { + return getSbn().getNotification().isMediaNotification(); + } else { + if (row == null) return false; - return row.isMediaRow(); + return row.isMediaRow(); + } } public boolean containsCustomViews() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java index efedfef5cbe9..c5a479180329 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineEntry.java @@ -19,5 +19,5 @@ package com.android.systemui.statusbar.notification.collection; /** * Class to represent a notification, group, or bundle in the pipeline. */ -public class PipelineEntry { +public abstract class PipelineEntry { } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java index 9c1d0735a65b..ac11c15e8bf8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java @@ -67,6 +67,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt; import com.android.systemui.util.Assert; import com.android.systemui.util.NamedListenerSet; @@ -1282,7 +1283,13 @@ public class ShadeListBuilder implements Dumpable, PipelineDumpable { entry.getAttachState().setExcludingFilter(filter); if (filter != null) { // notification is removed from the list, so we reset its initialization time - entry.resetInitializationTime(); + if (NotificationBundleUi.isEnabled()) { + if (entry.getRow() != null) { + entry.getRow().resetInitializationTime(); + } + } else { + entry.resetInitializationTime(); + } } return filter != null; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java index 733b986b5422..9df4bf4af4e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ColorizedFgsCoordinator.java @@ -23,6 +23,7 @@ import android.app.Notification; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -31,29 +32,50 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi; +import com.android.systemui.statusbar.notification.promoted.domain.interactor.PromotedNotificationsInteractor; import com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt; +import com.android.systemui.util.kotlin.JavaAdapterKt; -import com.google.common.primitives.Booleans; +import kotlinx.coroutines.CoroutineScope; + +import java.util.Collections; +import java.util.List; import javax.inject.Inject; /** * Handles sectioning for foreground service notifications. - * Puts non-min colorized foreground service notifications into the FGS section. See - * {@link NotifCoordinators} for section ordering priority. + * Puts non-min colorized foreground service notifications into the FGS section. See + * {@link NotifCoordinators} for section ordering priority. */ @CoordinatorScope public class ColorizedFgsCoordinator implements Coordinator { private static final String TAG = "ColorizedCoordinator"; + private final PromotedNotificationsInteractor mPromotedNotificationsInteractor; + private final CoroutineScope mMainScope; + + private List<String> mOrderedPromotedNotifKeys = Collections.emptyList(); @Inject - public ColorizedFgsCoordinator() { + public ColorizedFgsCoordinator( + @Application CoroutineScope mainScope, + PromotedNotificationsInteractor promotedNotificationsInteractor + ) { + mPromotedNotificationsInteractor = promotedNotificationsInteractor; + mMainScope = mainScope; } @Override - public void attach(NotifPipeline pipeline) { + public void attach(@NonNull NotifPipeline pipeline) { if (PromotedNotificationUi.isEnabled()) { pipeline.addPromoter(mPromotedOngoingPromoter); + + JavaAdapterKt.collectFlow(mMainScope, + mPromotedNotificationsInteractor.getOrderedChipNotificationKeys(), + (List<String> keys) -> { + mOrderedPromotedNotifKeys = keys; + mNotifSectioner.invalidateList("updated mOrderedPromotedNotifKeys"); + }); } } @@ -82,12 +104,24 @@ public class ColorizedFgsCoordinator implements Coordinator { return false; } - private NotifComparator mPreferPromoted = new NotifComparator("PreferPromoted") { + /** get the sort key for any entry in the ongoing section */ + private int getSortKey(@Nullable NotificationEntry entry) { + if (entry == null) return Integer.MAX_VALUE; + // Order all promoted notif keys first, using their order in the list + final int index = mOrderedPromotedNotifKeys.indexOf(entry.getKey()); + if (index >= 0) return index; + // Next, prioritize promoted ongoing over other notifications + return isPromotedOngoing(entry) ? Integer.MAX_VALUE - 1 : Integer.MAX_VALUE; + } + + private final NotifComparator mOngoingComparator = new NotifComparator( + "OngoingComparator") { @Override public int compare(@NonNull ListEntry o1, @NonNull ListEntry o2) { - return -1 * Booleans.compare( - isPromotedOngoing(o1.getRepresentativeEntry()), - isPromotedOngoing(o2.getRepresentativeEntry())); + return Integer.compare( + getSortKey(o1.getRepresentativeEntry()), + getSortKey(o2.getRepresentativeEntry()) + ); } }; @@ -95,7 +129,7 @@ public class ColorizedFgsCoordinator implements Coordinator { @Override public NotifComparator getComparator() { if (PromotedNotificationUi.isEnabled()) { - return mPreferPromoted; + return mOngoingComparator; } else { return null; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java index d47fe20911f9..2e3ab926ad57 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java @@ -27,6 +27,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import java.util.List; @@ -129,21 +130,42 @@ public class HighPriorityProvider { >= NotificationManager.IMPORTANCE_DEFAULT); } + /** + * Returns whether the given ListEntry has a high priority child or is in a group with a child + * that's high priority + */ private boolean hasHighPriorityChild(ListEntry entry, boolean allowImplicit) { - if (entry instanceof NotificationEntry - && !mGroupMembershipManager.isGroupSummary((NotificationEntry) entry)) { - return false; - } - - List<NotificationEntry> children = mGroupMembershipManager.getChildren(entry); - if (children != null) { - for (NotificationEntry child : children) { - if (child != entry && isHighPriority(child, allowImplicit)) { - return true; + if (NotificationBundleUi.isEnabled()) { + GroupEntry representativeGroupEntry = null; + if (entry instanceof GroupEntry) { + representativeGroupEntry = (GroupEntry) entry; + } else if (entry instanceof NotificationEntry){ + final NotificationEntry notificationEntry = entry.getRepresentativeEntry(); + if (notificationEntry.getParent() != null + && notificationEntry.getParent().getSummary() != null + && notificationEntry.getParent().getSummary() == notificationEntry) { + representativeGroupEntry = notificationEntry.getParent(); } } + return representativeGroupEntry != null && + representativeGroupEntry.getChildren().stream().anyMatch( + childEntry -> isHighPriority(childEntry, allowImplicit)); + + } else { + if (entry instanceof NotificationEntry + && !mGroupMembershipManager.isGroupSummary((NotificationEntry) entry)) { + return false; + } + List<NotificationEntry> children = mGroupMembershipManager.getChildren(entry); + if (children != null) { + for (NotificationEntry child : children) { + if (child != entry && isHighPriority(child, allowImplicit)) { + return true; + } + } + } + return false; } - return false; } private boolean hasHighPriorityCharacteristics(NotificationEntry entry) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java index 30386ab46382..ea369463da51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManager.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.collection.render; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -38,6 +39,20 @@ public interface GroupExpansionManager { boolean isGroupExpanded(NotificationEntry entry); /** + * Whether the parent associated with this notification is expanded. + * If this notification is not part of a group or bundle, it will always return false. + */ + boolean isGroupExpanded(EntryAdapter entry); + + /** + * Set whether the group/bundle associated with this notification is expanded or not. + */ + void setGroupExpanded(EntryAdapter entry, boolean expanded); + + /** @return group/bundle expansion state after toggling. */ + boolean toggleGroupExpansion(EntryAdapter entry); + + /** * Set whether the group associated with this notification is expanded or not. */ void setGroupExpanded(NotificationEntry entry, boolean expanded); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java index d1aff80b4e7c..16b98e20498a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java @@ -23,11 +23,13 @@ import androidx.annotation.NonNull; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import java.io.PrintWriter; import java.util.ArrayList; @@ -55,6 +57,8 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl */ private final Set<NotificationEntry> mExpandedGroups = new HashSet<>(); + private final Set<EntryAdapter> mExpandedCollections = new HashSet<>(); + @Inject public GroupExpansionManagerImpl(DumpManager dumpManager, GroupMembershipManager groupMembershipManager) { @@ -63,11 +67,17 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl } /** - * Cleanup entries from mExpandedGroups that no longer exist in the pipeline. + * Cleanup entries from internal tracking that no longer exist in the pipeline. */ private final OnBeforeRenderListListener mNotifTracker = (entries) -> { - if (mExpandedGroups.isEmpty()) { - return; // nothing to do + if (NotificationBundleUi.isEnabled()) { + if (mExpandedCollections.isEmpty()) { + return; // nothing to do + } + } else { + if (mExpandedGroups.isEmpty()) { + return; // nothing to do + } } final Set<NotificationEntry> renderingSummaries = new HashSet<>(); @@ -77,10 +87,25 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl } } - // If a group is in mExpandedGroups but not in the pipeline entries, collapse it. - final var groupsToRemove = setDifference(mExpandedGroups, renderingSummaries); - for (NotificationEntry entry : groupsToRemove) { - setGroupExpanded(entry, false); + if (NotificationBundleUi.isEnabled()) { + for (EntryAdapter entryAdapter : mExpandedCollections) { + boolean isInPipeline = false; + for (NotificationEntry entry : renderingSummaries) { + if (entry.getKey().equals(entryAdapter.getKey())) { + isInPipeline = true; + break; + } + } + if (!isInPipeline) { + setGroupExpanded(entryAdapter, false); + } + } + } else { + // If a group is in mExpandedGroups but not in the pipeline entries, collapse it. + final var groupsToRemove = setDifference(mExpandedGroups, renderingSummaries); + for (NotificationEntry entry : groupsToRemove) { + setGroupExpanded(entry, false); + } } }; @@ -96,11 +121,13 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl @Override public boolean isGroupExpanded(NotificationEntry entry) { + NotificationBundleUi.assertInLegacyMode(); return mExpandedGroups.contains(mGroupMembershipManager.getGroupSummary(entry)); } @Override public void setGroupExpanded(NotificationEntry entry, boolean expanded) { + NotificationBundleUi.assertInLegacyMode(); NotificationEntry groupSummary = mGroupMembershipManager.getGroupSummary(entry); if (entry.getParent() == null) { if (expanded) { @@ -127,14 +154,61 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl @Override public boolean toggleGroupExpansion(NotificationEntry entry) { + NotificationBundleUi.assertInLegacyMode(); + setGroupExpanded(entry, !isGroupExpanded(entry)); + return isGroupExpanded(entry); + } + + @Override + public boolean isGroupExpanded(EntryAdapter entry) { + NotificationBundleUi.assertInNewMode(); + return mExpandedCollections.contains(mGroupMembershipManager.getGroupRoot(entry)); + } + + @Override + public void setGroupExpanded(EntryAdapter entry, boolean expanded) { + NotificationBundleUi.assertInNewMode(); + EntryAdapter groupParent = mGroupMembershipManager.getGroupRoot(entry); + if (!entry.isAttached()) { + if (expanded) { + Log.wtf(TAG, "Cannot expand group that is not attached"); + } else { + // The entry is no longer attached, but we still want to make sure we don't have + // a stale expansion state. + groupParent = entry; + } + } + + boolean changed; + if (expanded) { + changed = mExpandedCollections.add(groupParent); + } else { + changed = mExpandedCollections.remove(groupParent); + } + + // Only notify listeners if something changed. + if (changed) { + sendOnGroupExpandedChange(entry, expanded); + } + } + + @Override + public boolean toggleGroupExpansion(EntryAdapter entry) { + NotificationBundleUi.assertInNewMode(); setGroupExpanded(entry, !isGroupExpanded(entry)); return isGroupExpanded(entry); } @Override public void collapseGroups() { - for (NotificationEntry entry : new ArrayList<>(mExpandedGroups)) { - setGroupExpanded(entry, false); + if (NotificationBundleUi.isEnabled()) { + for (EntryAdapter entry : new ArrayList<>(mExpandedCollections)) { + setGroupExpanded(entry, false); + } + } else { + for (NotificationEntry entry : new ArrayList<>(mExpandedGroups)) { + setGroupExpanded(entry, false); + } } } @@ -145,9 +219,21 @@ public class GroupExpansionManagerImpl implements GroupExpansionManager, Dumpabl for (NotificationEntry entry : mExpandedGroups) { pw.println(" * " + entry.getKey()); } + pw.println(" mExpandedCollection: " + mExpandedCollections.size()); + for (EntryAdapter entry : mExpandedCollections) { + pw.println(" * " + entry.getKey()); + } } private void sendOnGroupExpandedChange(NotificationEntry entry, boolean expanded) { + NotificationBundleUi.assertInLegacyMode(); + for (OnGroupExpansionChangeListener listener : mOnGroupChangeListeners) { + listener.onGroupExpansionChange(entry.getRow(), expanded); + } + } + + private void sendOnGroupExpandedChange(EntryAdapter entry, boolean expanded) { + NotificationBundleUi.assertInNewMode(); for (OnGroupExpansionChangeListener listener : mOnGroupChangeListeners) { listener.onGroupExpansionChange(entry.getRow(), expanded); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java index 3158782e6fea..69267e5d9e55 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.notification.collection.render; import android.annotation.NonNull; import android.annotation.Nullable; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -29,6 +30,13 @@ import java.util.List; * generally assumes that the notification is attached (aka its parent is not null). */ public interface GroupMembershipManager { + + /** + * @return whether a given entry is the root (GroupEntry or BundleEntry) in a collection which + * has children + */ + boolean isGroupRoot(@NonNull EntryAdapter entry); + /** * @return whether a given notification is the summary in a group which has children */ @@ -42,16 +50,15 @@ public interface GroupMembershipManager { NotificationEntry getGroupSummary(@NonNull NotificationEntry entry); /** - * Similar to {@link #getGroupSummary(NotificationEntry)} but doesn't get the visual summary - * but the logical summary, i.e when a child is isolated, it still returns the summary as if - * it wasn't isolated. - * TODO: remove this when migrating to the new pipeline, this is taken care of in the - * dismissal logic built into NotifCollection + * Gets the EntryAdapter that is the nearest root of the collection of rows the given entry + * belongs to. If the given entry is a BundleEntry or an isolated child of a BundleEntry, the + * BundleEntry will be returned. If the given notification is a group summary NotificationEntry, + * or a child of a group summary, the summary NotificationEntry will be returned, even if that + * summary belongs to a BundleEntry. If the entry is a notification that does not belong to any + * group or bundle grouping, null will be returned. */ @Nullable - default NotificationEntry getLogicalGroupSummary(@NonNull NotificationEntry entry) { - return getGroupSummary(entry); - } + EntryAdapter getGroupRoot(@NonNull EntryAdapter entry); /** * @return whether a given notification is a child in a group @@ -59,9 +66,10 @@ public interface GroupMembershipManager { boolean isChildInGroup(@NonNull NotificationEntry entry); /** - * Whether this is the only child in a group + * @return whether a given notification is a child in a group. The group may be a notification + * group or a bundle. */ - boolean isOnlyChildInGroup(@NonNull NotificationEntry entry); + boolean isChildInGroup(@NonNull EntryAdapter entry); /** * Get the children that are in the summary's group, not including those isolated. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java index da1247953c4c..80a9f8adf8f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java @@ -22,9 +22,11 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import java.util.List; @@ -41,6 +43,7 @@ public class GroupMembershipManagerImpl implements GroupMembershipManager { @Override public boolean isGroupSummary(@NonNull NotificationEntry entry) { + NotificationBundleUi.assertInLegacyMode(); if (entry.getParent() == null) { // The entry is not attached, so it doesn't count. return false; @@ -49,33 +52,47 @@ public class GroupMembershipManagerImpl implements GroupMembershipManager { return entry.getParent().getSummary() == entry; } + @Override + public boolean isGroupRoot(@NonNull EntryAdapter entry) { + NotificationBundleUi.assertInNewMode(); + return entry == entry.getGroupRoot(); + } + @Nullable @Override public NotificationEntry getGroupSummary(@NonNull NotificationEntry entry) { + NotificationBundleUi.assertInLegacyMode(); if (isTopLevelEntry(entry) || entry.getParent() == null) { return null; } return entry.getParent().getSummary(); } + @Nullable + @Override + public EntryAdapter getGroupRoot(@NonNull EntryAdapter entry) { + NotificationBundleUi.assertInNewMode(); + return entry.getGroupRoot(); + } + @Override public boolean isChildInGroup(@NonNull NotificationEntry entry) { + NotificationBundleUi.assertInLegacyMode(); // An entry is a child if it's not a summary or top level entry, but it is attached. return !isGroupSummary(entry) && !isTopLevelEntry(entry) && entry.getParent() != null; } @Override - public boolean isOnlyChildInGroup(@NonNull NotificationEntry entry) { - if (entry.getParent() == null) { - return false; // The entry is not attached. - } - - return !isGroupSummary(entry) && entry.getParent().getChildren().size() == 1; + public boolean isChildInGroup(@NonNull EntryAdapter entry) { + NotificationBundleUi.assertInNewMode(); + // An entry is a child if it's not a group root or top level entry, but it is attached. + return entry.isAttached() && entry != getGroupRoot(entry) && !entry.isTopLevelEntry(); } @Nullable @Override public List<NotificationEntry> getChildren(@NonNull ListEntry entry) { + NotificationBundleUi.assertInLegacyMode(); if (entry instanceof GroupEntry) { return ((GroupEntry) entry).getChildren(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt index ccc2dffcfd7b..867db8ec8235 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt @@ -49,7 +49,7 @@ constructor( ) : Dumpable { private val tag = "AvalancheController" - private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG) + private val debug = false // Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG) var baseEntryMapStr: () -> String = { "baseEntryMapStr not initialized" } var enableAtRuntime = true @@ -163,6 +163,7 @@ constructor( if (entry in nextMap) nextMap.remove(entry) if (entry in nextList) nextList.remove(entry) + outcome = "add next" addToNext(entry, runnable) // Shorten headsUpEntryShowing display time @@ -174,7 +175,7 @@ constructor( headsUpEntryShowing!!.updateEntry( /* updatePostTime= */ false, /* updateEarliestRemovalTime= */ false, - /* reason= */ "avalanche duration update", + /* reason= */ "shorten duration of previously-last HUN", ) } } @@ -269,8 +270,10 @@ constructor( } nextList.sort() val entryList = showingList + nextList + val thisKey = getKey(entry) if (entryList.isEmpty()) { - log { "No avalanche HUNs, use default ms: $autoDismissMs" } + headsUpManagerLogger.logAvalancheDuration( + thisKey, autoDismissMs, "No avalanche HUNs, use default", nextKey = "") return autoDismissMs } // entryList.indexOf(entry) returns -1 even when the entry is in entryList @@ -281,27 +284,29 @@ constructor( } } if (thisEntryIndex == -1) { - log { "Untracked entry, use default ms: $autoDismissMs" } + headsUpManagerLogger.logAvalancheDuration( + thisKey, autoDismissMs, "Untracked entry, use default", nextKey = "") return autoDismissMs } val nextEntryIndex = thisEntryIndex + 1 - - // If last entry, use default duration if (nextEntryIndex >= entryList.size) { - log { "Last entry, use default ms: $autoDismissMs" } + headsUpManagerLogger.logAvalancheDuration( + thisKey, autoDismissMs, "Last entry, use default", nextKey = "") return autoDismissMs } val nextEntry = entryList[nextEntryIndex] + val nextKey = getKey(nextEntry) if (nextEntry.compareNonTimeFields(entry) == -1) { - // Next entry is higher priority - log { "Next entry is higher priority: 500ms" } + headsUpManagerLogger.logAvalancheDuration( + thisKey, 500, "LOWER priority than next: ", nextKey) return 500 } else if (nextEntry.compareNonTimeFields(entry) == 0) { - // Next entry is same priority - log { "Next entry is same priority: 1000ms" } + headsUpManagerLogger.logAvalancheDuration( + thisKey, 1000, "SAME priority as next: ", nextKey) return 1000 } else { - log { "Next entry is lower priority, use default ms: $autoDismissMs" } + headsUpManagerLogger.logAvalancheDuration( + thisKey, autoDismissMs, "HIGHER priority than next: ", nextKey) return autoDismissMs } } @@ -355,25 +360,28 @@ constructor( } private fun showNow(entry: HeadsUpEntry, runnableList: MutableList<Runnable>) { - log { "SHOW: " + getKey(entry) } - + headsUpManagerLogger.logAvalancheStage("show", getKey(entry)) uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_SHOWN) headsUpEntryShowing = entry - runnableList.forEach { - if (it in debugRunnableLabelMap) { - log { "RUNNABLE: ${debugRunnableLabelMap[it]}" } + runnableList.forEach { runnable -> + if (debug) { + debugRunnableLabelMap[runnable]?.let { label -> + headsUpManagerLogger.logAvalancheStage("run", label) + // Remove label after logging to avoid memory leak + debugRunnableLabelMap.remove(runnable) + } } - it.run() + runnable.run() } } private fun showNext() { - log { "SHOW NEXT" } + headsUpManagerLogger.logAvalancheStage("show next", key = "") headsUpEntryShowing = null if (nextList.isEmpty()) { - log { "NO MORE TO SHOW" } + headsUpManagerLogger.logAvalancheStage("no more", key = "") previousHunKey = "" return } @@ -395,11 +403,7 @@ constructor( debugRunnableLabelMap.remove(r) } } - val queue = ArrayList<String>() - for (entry in listToDrop) { - queue.add("[${getKey(entry)}]") - } - val dropList = java.lang.String.join("\n", queue) + val dropList = listToDrop.joinToString("\n ") { getKey(it) } headsUpManagerLogger.logDroppedHuns(dropList) } clearNext() @@ -424,38 +428,24 @@ constructor( // Methods below are for logging only ========================================================== - private inline fun log(s: () -> String) { - if (debug) { - Log.d(tag, s()) - } - } - private fun getStateStr(): String { - return "\navalanche state:" + - "\n\tshowing: [${getKey(headsUpEntryShowing)}]" + - "\n\tprevious: [$previousHunKey]" + - "\n\tnext list: $nextListStr" + - "\n\tnext map: $nextMapStr" + - "\nBHUM.mHeadsUpEntryMap: " + - baseEntryMapStr() + return "\n[AC state]" + + "\nshow: ${getKey(headsUpEntryShowing)}" + + "\nprevious: $previousHunKey" + + "\n$nextStr" + + "\n[HeadsUpManagerImpl.mHeadsUpEntryMap] " + baseEntryMapStr() + "\n" } - private val nextListStr: String + private val nextStr: String get() { - val queue = ArrayList<String>() - for (entry in nextList) { - queue.add("[${getKey(entry)}]") + val nextListStr = nextList.joinToString("\n ") { getKey(it) } + if (nextList.toSet() == nextMap.keys.toSet()) { + return "next (${nextList.size}):\n $nextListStr" } - return java.lang.String.join("\n", queue) - } - - private val nextMapStr: String - get() { - val queue = ArrayList<String>() - for (entry in nextMap.keys) { - queue.add("[${getKey(entry)}]") - } - return java.lang.String.join("\n", queue) + // This should never happen + val nextMapStr = nextMap.keys.joinToString("\n ") { getKey(it) } + return "next list (${nextList.size}):\n $nextListStr" + + "\nnext map (${nextMap.size}):\n $nextMapStr" } fun getKey(entry: HeadsUpEntry?): String { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java index be61dc95fe20..87b9bf87c680 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java @@ -46,6 +46,7 @@ import com.android.systemui.shade.ShadeDisplayAware; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator; import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener; @@ -55,6 +56,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember import com.android.systemui.statusbar.notification.data.repository.HeadsUpRepository; import com.android.systemui.statusbar.notification.data.repository.HeadsUpRowRepository; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun; import com.android.systemui.statusbar.phone.ExpandHeadsUpOnInlineReply; import com.android.systemui.statusbar.phone.KeyguardBypassController; @@ -118,7 +120,8 @@ public class HeadsUpManagerImpl @VisibleForTesting final ArrayMap<String, HeadsUpEntry> mHeadsUpEntryMap = new ArrayMap<>(); private final HeadsUpManagerLogger mLogger; - private final int mMinimumDisplayTime; + private final int mMinimumDisplayTimeDefault; + private final int mMinimumDisplayTimeForUserInitiated; private final int mStickyForSomeTimeAutoDismissTime; private final int mAutoDismissTime; private final DelayableExecutor mExecutor; @@ -215,9 +218,11 @@ public class HeadsUpManagerImpl mGroupMembershipManager = groupMembershipManager; mVisualStabilityProvider = visualStabilityProvider; Resources resources = context.getResources(); - mMinimumDisplayTime = NotificationThrottleHun.isEnabled() + mMinimumDisplayTimeDefault = NotificationThrottleHun.isEnabled() ? resources.getInteger(R.integer.heads_up_notification_minimum_time_with_throttling) : resources.getInteger(R.integer.heads_up_notification_minimum_time); + mMinimumDisplayTimeForUserInitiated = resources.getInteger( + R.integer.heads_up_notification_minimum_time_for_user_initiated); mStickyForSomeTimeAutoDismissTime = resources.getInteger( R.integer.sticky_heads_up_notification_time); mAutoDismissTime = resources.getInteger(R.integer.heads_up_notification_decay); @@ -851,11 +856,11 @@ public class HeadsUpManagerImpl private String getEntryMapStr() { if (mHeadsUpEntryMap.isEmpty()) { - return "EMPTY"; + return ""; } StringBuilder entryMapStr = new StringBuilder(); for (HeadsUpEntry entry: mHeadsUpEntryMap.values()) { - entryMapStr.append("\n\t").append( + entryMapStr.append("\n ").append( entry.mEntry == null ? "null" : entry.mEntry.getKey()); } return entryMapStr.toString(); @@ -871,14 +876,24 @@ public class HeadsUpManagerImpl if (!hasPinnedHeadsUp() || topEntry == null) { return null; } else { + ExpandableNotificationRow topRow = topEntry.getRow(); if (topEntry.rowIsChildInGroup()) { - final NotificationEntry groupSummary = - mGroupMembershipManager.getGroupSummary(topEntry); - if (groupSummary != null) { - topEntry = groupSummary; + if (NotificationBundleUi.isEnabled()) { + final EntryAdapter adapter = mGroupMembershipManager.getGroupRoot( + topRow.getEntryAdapter()); + if (adapter != null) { + topRow = adapter.getRow(); + } + } else { + final NotificationEntry groupSummary = + mGroupMembershipManager.getGroupSummary(topEntry); + if (groupSummary != null) { + topEntry = groupSummary; + topRow = topEntry.getRow(); + } } } - ExpandableNotificationRow topRow = topEntry.getRow(); + int[] tmpArray = new int[2]; topRow.getLocationOnScreen(tmpArray); int minX = tmpArray[0]; @@ -1358,7 +1373,12 @@ public class HeadsUpManagerImpl final long now = mSystemClock.elapsedRealtime(); if (updateEarliestRemovalTime) { - mEarliestRemovalTime = now + mMinimumDisplayTime; + if (StatusBarNotifChips.isEnabled() + && mPinnedStatus.getValue() == PinnedStatus.PinnedByUser) { + mEarliestRemovalTime = now + mMinimumDisplayTimeForUserInitiated; + } else { + mEarliestRemovalTime = now + mMinimumDisplayTimeDefault; + } } if (updatePostTime) { @@ -1377,7 +1397,7 @@ public class HeadsUpManagerImpl final long now = mSystemClock.elapsedRealtime(); return NotificationThrottleHun.isEnabled() ? Math.max(finishTime, mEarliestRemovalTime) - now - : Math.max(finishTime - now, mMinimumDisplayTime); + : Math.max(finishTime - now, mMinimumDisplayTimeDefault); }; scheduleAutoRemovalCallback(finishTimeCalculator, "updateEntry (not sticky)"); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt index 65fb9ca558d7..388d357b3b15 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt @@ -71,7 +71,7 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) { str3 = outcome bool1 = isEnabled }, - { "$str1\n\t=> AC[isEnabled:$bool1] update: $str2\n\t=> $str3" }, + { "$str1\n=> AC[enabled:$bool1] update: $str2\n=> $str3" }, ) } @@ -90,7 +90,33 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) { str3 = outcome bool1 = isEnabled }, - { "$str1\n\t=> AC[isEnabled:$bool1] delete: $str2\n\t=> $str3" }, + { "$str1\n=> AC[enabled:$bool1] delete: $str2\n=> $str3" }, + ) + } + + fun logAvalancheStage(stage: String, key: String) { + buffer.log( + TAG, + INFO, + { + str1 = stage + str2 = key + }, + { "[AC] $str1 $str2" }, + ) + } + + fun logAvalancheDuration(thisKey: String, duration: Int, reason: String, nextKey: String) { + buffer.log( + TAG, + INFO, + { + str1 = thisKey + int1 = duration + str2 = reason + str3 = nextKey + }, + { "[AC] $str1 | $int1 ms | $str2 $str3" }, ) } @@ -325,7 +351,7 @@ constructor(@NotificationHeadsUpLog private val buffer: LogBuffer) { } fun logDroppedHuns(entryList: String) { - buffer.log(TAG, VERBOSE, { str1 = entryList }, { "[AC] Drop HUNs: $str1" }) + buffer.log(TAG, VERBOSE, { str1 = entryList }, { "[AC] dropped:\n $str1" }) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java index 3b6b9ed636fe..47e725cb5e8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpTouchHelper.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.headsup; +import android.annotation.Nullable; import android.content.Context; import android.os.RemoteException; import android.view.MotionEvent; @@ -210,10 +211,12 @@ public class HeadsUpTouchHelper implements Gefingerpoken { if (mHeadsUpManager.shouldSwallowClick( mPickedChild.getEntry().getSbn().getKey())) { endMotion(); + setTrackingHeadsUp(false); return true; } } endMotion(); + setTrackingHeadsUp(false); return false; } return false; @@ -258,7 +261,7 @@ public class HeadsUpTouchHelper implements Gefingerpoken { void setHeadsUpDraggingStartingHeight(int startHeight); /** Sets notification that is being expanded. */ - void setTrackedHeadsUp(ExpandableNotificationRow expandableNotificationRow); + void setTrackedHeadsUp(@Nullable ExpandableNotificationRow expandableNotificationRow); /** Called when a MotionEvent is about to trigger expansion. */ void startExpand(float newX, float newY, boolean startTracking, float expandedHeight); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt index 691f1f452da8..f755dbb48e1d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt @@ -27,6 +27,7 @@ import com.android.systemui.statusbar.notification.people.PeopleNotificationIden import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import javax.inject.Inject import kotlin.math.max @@ -112,14 +113,26 @@ class PeopleNotificationIdentifierImpl @Inject constructor( if (personExtractor.isPersonNotification(sbn)) TYPE_PERSON else TYPE_NON_PERSON private fun getPeopleTypeOfSummary(entry: NotificationEntry): Int { - if (!groupManager.isGroupSummary(entry)) { - return TYPE_NON_PERSON + if (NotificationBundleUi.isEnabled) { + if (!entry.sbn.notification.isGroupSummary) { + return TYPE_NON_PERSON; + } + + return getPeopleTypeForChildList(entry.parent?.children) + } else { + if (!groupManager.isGroupSummary(entry)) { + return TYPE_NON_PERSON + } + + return getPeopleTypeForChildList(groupManager.getChildren(entry)) } + } - val childTypes = groupManager.getChildren(entry) - ?.asSequence() - ?.map { getPeopleNotificationType(it) } - ?: return TYPE_NON_PERSON + private fun getPeopleTypeForChildList(children: List<NotificationEntry>?): Int { + val childTypes = children + ?.asSequence() + ?.map { getPeopleNotificationType(it) } + ?: return TYPE_NON_PERSON var groupType = TYPE_NON_PERSON for (childType in childTypes) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt index 893570b7fb51..7959e99f3189 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AODPromotedNotification.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.promoted import android.app.Flags +import android.app.Flags.notificationsRedesignTemplates import android.app.Notification import android.graphics.PorterDuff import android.view.LayoutInflater @@ -166,7 +167,10 @@ private class AODPromotedNotificationViewUpdater(root: View) { private val closeButton: View? = root.findViewById(R.id.close_button) private val conversationIconBadge: View? = root.findViewById(R.id.conversation_icon_badge) private val conversationIcon: CachingIconView? = root.findViewById(R.id.conversation_icon) - private val conversationText: TextView? = root.findViewById(R.id.conversation_text) + private val conversationText: TextView? = + root.findViewById( + if (notificationsRedesignTemplates()) R.id.title else R.id.conversation_text + ) private val expandButton: NotificationExpandButton? = root.findViewById(R.id.expand_button) private val headerText: TextView? = root.findViewById(R.id.header_text) private val headerTextDivider: View? = root.findViewById(R.id.header_text_divider) @@ -386,24 +390,21 @@ private class AODPromotedNotificationViewUpdater(root: View) { setTextViewColor(time, SecondaryText) setTextViewColor(chronometer, SecondaryText) - val timeValue = content.time + if (content.time is When.Time) { + time?.setTime(content.time.currentTimeMillis) + } - if (timeValue == null) { - time?.visibility = GONE - chronometer?.visibility = GONE - } else if (timeValue.mode == When.Mode.BasicTime) { - time?.visibility = VISIBLE - time?.setTime(timeValue.time) - chronometer?.visibility = GONE - } else { + if (content.time is When.Chronometer) { inflateChronometer() - - time?.visibility = GONE - chronometer?.visibility = VISIBLE - chronometer?.base = timeValue.time - chronometer?.isCountDown = (timeValue.mode == When.Mode.CountDown) + chronometer?.base = content.time.elapsedRealtimeMillis + chronometer?.isCountDown = content.time.isCountDown chronometer?.setStarted(true) + } else { + chronometer?.stop() } + + time?.isVisible = (content.time is When.Time) + chronometer?.isVisible = (content.time is When.Chronometer) } private fun updateSmallIcon( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt index 39c7df064c8c..2aafe8c81381 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt @@ -48,6 +48,7 @@ import com.android.systemui.statusbar.notification.row.shared.ImageModelProvider import com.android.systemui.statusbar.notification.row.shared.ImageModelProvider.ImageSizeClass.MediumSquare import com.android.systemui.statusbar.notification.row.shared.ImageModelProvider.ImageSizeClass.SmallSquare import com.android.systemui.statusbar.notification.row.shared.SkeletonImageTransform +import com.android.systemui.util.time.SystemClock import javax.inject.Inject interface PromotedNotificationContentExtractor { @@ -64,6 +65,7 @@ class PromotedNotificationContentExtractorImpl constructor( @ShadeDisplayAware private val context: Context, private val skeletonImageTransform: SkeletonImageTransform, + private val systemClock: SystemClock, private val logger: PromotedNotificationLogger, ) : PromotedNotificationContentExtractor { override fun extractContent( @@ -168,15 +170,17 @@ constructor( extras?.getBoolean(EXTRA_PROGRESS_INDETERMINATE) private fun Notification.extractWhen(): When? { - val time = `when` - val showsTime = showsTime() - val showsChronometer = showsChronometer() - val countDown = chronometerCountDown() - return when { - showsTime -> When(time, When.Mode.BasicTime) - showsChronometer -> - When(time, if (countDown) When.Mode.CountDown else When.Mode.CountUp) + showsChronometer() -> { + When.Chronometer( + elapsedRealtimeMillis = + `when` + systemClock.elapsedRealtime() - systemClock.currentTimeMillis(), + isCountDown = chronometerCountDown(), + ) + } + + showsTime() -> When.Time(currentTimeMillis = `when`) + else -> null } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt index 393f95d3ad77..4bc685423659 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.promoted.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager -import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style import com.android.systemui.util.kotlin.FlowDumperImpl @@ -30,13 +29,12 @@ import kotlinx.coroutines.flow.map class AODPromotedNotificationInteractor @Inject constructor( - activeNotificationsInteractor: ActiveNotificationsInteractor, + promotedNotificationsInteractor: PromotedNotificationsInteractor, dumpManager: DumpManager, ) : FlowDumperImpl(dumpManager) { + /** The content to show as the promoted notification on AOD */ val content: Flow<PromotedNotificationContentModel?> = - activeNotificationsInteractor.topLevelRepresentativeNotifications.map { notifs -> - notifs.firstNotNullOfOrNull { it.promotedContent } - } + promotedNotificationsInteractor.topPromotedNotificationContent val isPresent: Flow<Boolean> = content diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt new file mode 100644 index 000000000000..1015cfbefc41 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.promoted.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.statusbar.chips.call.domain.interactor.CallChipInteractor +import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor +import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor +import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel +import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +/** + * An interactor that provides details about promoted notification precedence, based on the + * presented order of current notification status bar chips. + */ +@SysUISingleton +class PromotedNotificationsInteractor +@Inject +constructor( + activeNotificationsInteractor: ActiveNotificationsInteractor, + callChipInteractor: CallChipInteractor, + notifChipsInteractor: StatusBarNotificationChipsInteractor, + @Background backgroundDispatcher: CoroutineDispatcher, +) { + /** + * This is the ordered list of notifications (and the promoted content) represented as chips in + * the status bar. + */ + private val orderedChipNotifications: Flow<List<NotifAndPromotedContent>> = + combine(callChipInteractor.ongoingCallState, notifChipsInteractor.allNotificationChips) { + callState, + notifChips -> + buildList { + val callData = callState.getNotifData()?.also { add(it) } + addAll( + notifChips.mapNotNull { + when (it.key) { + callData?.key -> null // do not re-add the same call + else -> NotifAndPromotedContent(it.key, it.promotedContent) + } + } + ) + } + } + + private fun OngoingCallModel.getNotifData(): NotifAndPromotedContent? = + when (this) { + is OngoingCallModel.InCall -> NotifAndPromotedContent(notificationKey, promotedContent) + is OngoingCallModel.InCallWithVisibleApp -> + // TODO(b/395989259): support InCallWithVisibleApp when it has notif data + null + is OngoingCallModel.NoCall -> null + } + + /** + * The top promoted notification represented by a chip, with the order determined by the order + * of the chips, not the notifications. + */ + private val topPromotedChipNotification: Flow<PromotedNotificationContentModel?> = + orderedChipNotifications + .map { list -> list.firstNotNullOfOrNull { it.promotedContent } } + .distinctUntilNewInstance() + + /** This is the top-most promoted notification, which should avoid regular changing. */ + val topPromotedNotificationContent: Flow<PromotedNotificationContentModel?> = + combine( + topPromotedChipNotification, + activeNotificationsInteractor.topLevelRepresentativeNotifications, + ) { topChipNotif, topLevelNotifs -> + topChipNotif ?: topLevelNotifs.firstNotNullOfOrNull { it.promotedContent } + } + // #equals() can be a bit expensive on this object, but this flow will regularly try to + // emit the same immutable instance over and over, so just prevent that. + .distinctUntilNewInstance() + + /** + * This is the ordered list of notifications (and the promoted content) represented as chips in + * the status bar. Flows on the background context. + */ + val orderedChipNotificationKeys: Flow<List<String>> = + orderedChipNotifications + .map { list -> list.map { it.key } } + .distinctUntilChanged() + .flowOn(backgroundDispatcher) + + /** + * Returns flow where all subsequent repetitions of the same object instance are filtered out. + */ + private fun <T> Flow<T>.distinctUntilNewInstance() = distinctUntilChanged { a, b -> a === b } + + /** + * A custom pair, but providing clearer semantic names, and implementing equality as being the + * same instance of the promoted content model, which allows us to use distinctUntilChanged() on + * flows containing this without doing pixel comparisons on the Bitmaps inside Icon objects + * provided by the Notification. + */ + private data class NotifAndPromotedContent( + val key: String, + val promotedContent: PromotedNotificationContentModel?, + ) { + /** + * Define the equals of this object to only check the reference equality of the promoted + * content so that we can mark. + */ + override fun equals(other: Any?): Boolean { + return when { + other == null -> false + other === this -> true + other !is NotifAndPromotedContent -> return false + else -> key == other.key && promotedContent === other.promotedContent + } + } + + /** Define the hashCode to be very quick, even if it increases collisions. */ + override fun hashCode(): Int { + var result = key.hashCode() + result = 31 * result + (promotedContent?.identity?.hashCode() ?: 0) + return result + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt index 38d41e37f916..0c2859fa1766 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt @@ -16,7 +16,9 @@ package com.android.systemui.statusbar.notification.promoted.shared.model +import android.annotation.CurrentTimeMillisLong import android.annotation.DrawableRes +import android.annotation.ElapsedRealtimeLong import android.app.Notification import android.app.Notification.FLAG_PROMOTED_ONGOING import androidx.annotation.ColorInt @@ -120,16 +122,18 @@ data class PromotedNotificationContentModel( data class Identity(val key: String, val style: Style) /** The timestamp associated with a notification, along with the mode used to display it. */ - data class When(val time: Long, val mode: Mode) { - /** The mode used to display a notification's `when` value. */ - enum class Mode { - /** No custom mode requested by the notification. */ - BasicTime, - /** Show the notification's time as a chronometer that counts down to [time]. */ - CountDown, - /** Show the notification's time as a chronometer that counts up from [time]. */ - CountUp, - } + sealed class When { + /** Show the notification's time as a timestamp. */ + data class Time(@CurrentTimeMillisLong val currentTimeMillis: Long) : When() + + /** + * Show the notification's time as a chronometer that counts up or down (based on + * [isCountDown]) to [elapsedRealtimeMillis]. + */ + data class Chronometer( + @ElapsedRealtimeLong val elapsedRealtimeMillis: Long, + val isCountDown: Boolean, + ) : When() } /** The colors used to display the notification. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index b4092cd785bf..b0773276a3e9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.Flags.notificationBackgroundTintOptimization; +import static com.android.systemui.Flags.notificationRowTransparency; import static com.android.systemui.statusbar.notification.row.ExpandableView.ClipSide.BOTTOM; import static com.android.systemui.statusbar.notification.row.ExpandableView.ClipSide.TOP; @@ -38,6 +39,7 @@ import com.android.app.animation.Interpolators; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.jank.InteractionJankMonitor.Configuration; import com.android.systemui.Gefingerpoken; +import com.android.systemui.common.shared.colors.SurfaceEffectColors; import com.android.systemui.res.R; import com.android.systemui.shade.TouchLogger; import com.android.systemui.statusbar.NotificationShelf; @@ -122,8 +124,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } private void updateColors() { - mNormalColor = mContext.getColor( - com.android.internal.R.color.materialColorSurfaceContainerHigh); + if (notificationRowTransparency()) { + mNormalColor = SurfaceEffectColors.surfaceEffect1(getResources()); + } else { + mNormalColor = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceContainerHigh); + } mTintedRippleColor = mContext.getColor( R.color.notification_ripple_tinted_color); mNormalRippleColor = mContext.getColor( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt new file mode 100644 index 000000000000..c3b241154e0e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AsyncRowInflater.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row + +import android.content.Context +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.LayoutRes +import androidx.annotation.UiThread +import com.android.app.tracing.coroutines.launchTraced +import com.android.app.tracing.coroutines.withContextTraced +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.dagger.qualifiers.NotifInflation +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job + +@SysUISingleton +class AsyncRowInflater +@Inject +constructor( + @Application private val applicationScope: CoroutineScope, + @Main private val mainCoroutineDispatcher: CoroutineDispatcher, + @NotifInflation private val inflationCoroutineDispatcher: CoroutineDispatcher, +) { + /** + * Inflate the layout on the background thread, and invoke the listener on the main thread when + * finished. + * + * If the inflation fails on the background, it will be retried once on the main thread. + */ + @UiThread + fun inflate( + context: Context, + layoutFactory: LayoutInflater.Factory2, + @LayoutRes resId: Int, + parent: ViewGroup, + listener: OnInflateFinishedListener, + ): Job { + val inflater = BasicRowInflater(context).apply { factory2 = layoutFactory } + return applicationScope.launchTraced("AsyncRowInflater-bg", inflationCoroutineDispatcher) { + val view = + try { + inflater.inflate(resId, parent, false) + } catch (ex: RuntimeException) { + // Probably a Looper failure, retry on the UI thread + Log.w( + "AsyncRowInflater", + "Failed to inflate resource in the background!" + + " Retrying on the UI thread", + ex, + ) + null + } + withContextTraced("AsyncRowInflater-ui", mainCoroutineDispatcher) { + // If the inflate failed on the inflation thread, try again on the main thread + val finalView = view ?: inflater.inflate(resId, parent, false) + // Inform the listener of the completion + listener.onInflateFinished(finalView, resId, parent) + } + } + } + + /** + * Callback interface (identical to the one from AsyncLayoutInflater) for receiving the inflated + * view + */ + interface OnInflateFinishedListener { + @UiThread fun onInflateFinished(view: View, @LayoutRes resId: Int, parent: ViewGroup?) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt new file mode 100644 index 000000000000..79d50b8398bc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/BasicRowInflater.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.statusbar.notification.row + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View + +/** + * A [LayoutInflater] that is copy of + * [androidx.asynclayoutinflater.view.AsyncLayoutInflater.BasicInflater] + */ +internal class BasicRowInflater(context: Context) : LayoutInflater(context) { + override fun cloneInContext(newContext: Context): LayoutInflater { + return BasicRowInflater(newContext) + } + + @Throws(ClassNotFoundException::class) + override fun onCreateView(name: String, attrs: AttributeSet): View { + for (prefix in sClassPrefixList) { + try { + val view = createView(name, prefix, attrs) + if (view != null) { + return view + } + } catch (e: ClassNotFoundException) { + // In this case we want to let the base class take a crack at it. + } + } + + return super.onCreateView(name, attrs) + } + + companion object { + private val sClassPrefixList = arrayOf("android.widget.", "android.webkit.", "android.app.") + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index fd334447e13a..6f7eade1c0f2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -21,7 +21,9 @@ import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_ import static android.service.notification.NotificationListenerService.REASON_CANCEL; import static com.android.systemui.Flags.notificationsPinnedHunInShade; +import static com.android.systemui.Flags.notificationRowTransparency; import static com.android.systemui.flags.Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE; +import static com.android.systemui.statusbar.notification.NotificationUtils.logKey; import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED; import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP; import static com.android.systemui.statusbar.policy.RemoteInputView.FOCUS_ANIMATION_MIN_SCALE; @@ -44,6 +46,7 @@ import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; @@ -105,6 +108,7 @@ import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.NotificationTransitionAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.SourceType; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; @@ -114,12 +118,12 @@ import com.android.systemui.statusbar.notification.headsup.PinnedStatus; import com.android.systemui.statusbar.notification.logging.NotificationCounters; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded; -import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation; import com.android.systemui.statusbar.notification.row.shared.LockscreenOtpRedaction; import com.android.systemui.statusbar.notification.row.wrapper.NotificationCompactMessagingTemplateViewWrapper; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization; import com.android.systemui.statusbar.notification.shared.TransparentHeaderFix; import com.android.systemui.statusbar.notification.stack.AmbientState; @@ -165,6 +169,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30); private static final SourceType BASE_VALUE = SourceType.from("BaseValue"); private static final SourceType FROM_PARENT = SourceType.from("FromParent(ENR)"); + private static final long INITIALIZATION_DELAY = 400; // We don't correctly track dark mode until the content views are inflated, so always update // the background on first content update just in case it happens to be during a theme change. @@ -263,11 +268,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private NotificationContentView mPublicLayout; private NotificationContentView mPrivateLayout; private NotificationContentView[] mLayouts; - private int mNotificationColor; private ExpandableNotificationRowLogger mLogger; private String mLoggingKey; private NotificationGuts mGuts; private NotificationEntry mEntry; + private EntryAdapter mEntryAdapter; private String mAppName; private NotificationRebindingTracker mRebindingTracker; private FalsingManager mFalsingManager; @@ -347,6 +352,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView */ private boolean mSaveSpaceOnLockscreen; + // indicates when this view was first attached to a window + // this value will reset when the view is completely removed from the shade (ie: filtered out) + private long initializationTime = -1; + /** * It is added for unit testing purpose. * Please do not use it for other purposes. @@ -390,11 +399,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } private void toggleExpansionState(View v, boolean shouldLogExpandClickMetric) { - if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) - && mGroupMembershipManager.isGroupSummary(mEntry)) { + boolean isGroupRoot = NotificationBundleUi.isEnabled() + ? mGroupMembershipManager.isGroupRoot(mEntryAdapter) + : mGroupMembershipManager.isGroupSummary(mEntry); + if (!shouldShowPublic() && (!mIsMinimized || isExpanded()) && isGroupRoot) { mGroupExpansionChanging = true; - final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry); - boolean nowExpanded = mGroupExpansionManager.toggleGroupExpansion(mEntry); + final boolean wasExpanded = NotificationBundleUi.isEnabled() + ? mGroupExpansionManager.isGroupExpanded(mEntryAdapter) + : mGroupExpansionManager.isGroupExpanded(mEntry); + boolean nowExpanded = NotificationBundleUi.isEnabled() + ? mGroupExpansionManager.toggleGroupExpansion(mEntryAdapter) + : mGroupExpansionManager.toggleGroupExpansion(mEntry); mOnExpandClickListener.onExpandClicked(mEntry, v, nowExpanded); if (shouldLogExpandClickMetric) { mMetricsLogger.action(MetricsEvent.ACTION_NOTIFICATION_GROUP_EXPANDER, nowExpanded); @@ -516,6 +531,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mPublicLayout; } + public String getLoggingKey() { + return mLoggingKey; + } + /** * Sets animations running in the layouts of this row, including public, private, and children. * @@ -610,26 +629,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } /** - * Marks a content view as freeable, setting it so that future inflations do not reinflate - * and ensuring that the view is freed when it is safe to remove. - * - * @param inflationFlag flag corresponding to the content view to be freed - * @deprecated By default, {@link NotificationRowContentBinder#unbindContent} will tell the - * view hierarchy to only free when the view is safe to remove so this method is no longer - * needed. Will remove when all uses are gone. - */ - @Deprecated - public void freeContentViewWhenSafe(@InflationFlag int inflationFlag) { - RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry); - params.markContentViewsFreeable(inflationFlag); - mRowContentBindStage.requestRebind(mEntry, null /* callback */); - } - - /** * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif * or is in an allowList). */ public boolean getIsNonblockable() { + NotificationBundleUi.assertInLegacyMode(); if (mEntry == null) { return true; } @@ -651,9 +655,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView l.onNotificationUpdated(mEntry); } mShowingPublicInitialized = false; - updateNotificationColor(); if (mMenuRow != null) { - mMenuRow.onNotificationUpdated(mEntry.getSbn()); + mMenuRow.onNotificationUpdated(); mMenuRow.setAppName(mAppName); } if (mIsSummaryWithChildren) { @@ -712,15 +715,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } /** - * Called when the notification's ranking was changed (but nothing else changed). - */ - public void onNotificationRankingUpdated() { - if (mMenuRow != null) { - mMenuRow.onNotificationUpdated(mEntry.getSbn()); - } - } - - /** * Call when bubble state has changed and the button on the notification should be updated. */ public void updateBubbleButton() { @@ -731,7 +725,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @VisibleForTesting void updateShelfIconColor() { - StatusBarIconView expandedIcon = mEntry.getIcons().getShelfIcon(); + StatusBarIconView expandedIcon = getShelfIcon(); boolean isPreL = Boolean.TRUE.equals(expandedIcon.getTag(R.id.icon_is_pre_L)); boolean colorize = !isPreL || NotificationUtils.isGrayscale(expandedIcon, ContrastColorUtil.getInstance(mContext)); @@ -752,8 +746,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (color != Notification.COLOR_INVALID) { return color; } else { - return mEntry.getContrastedColor(mContext, mIsMinimized && !isExpanded(), - getBackgroundColorWithoutTint()); + if (NotificationBundleUi.isEnabled()) { + return mEntryAdapter.getContrastedColor(mContext, mIsMinimized && !isExpanded(), + getBackgroundColorWithoutTint()); + } else { + return mEntry.getContrastedColor(mContext, mIsMinimized && !isExpanded(), + getBackgroundColorWithoutTint()); + } } } @@ -855,15 +854,29 @@ public class ExpandableNotificationRow extends ActivatableNotificationView boolean customView = contractedView != null && contractedView.getId() != com.android.internal.R.id.status_bar_latest_event_content; - boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N; - boolean beforeP = mEntry.targetSdk < Build.VERSION_CODES.P; - boolean beforeS = mEntry.targetSdk < Build.VERSION_CODES.S; + int targetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT; + if (NotificationBundleUi.isEnabled()) { + targetSdk = mEntryAdapter.getTargetSdk(); + } else { + targetSdk = mEntry.targetSdk; + } + + boolean beforeN = targetSdk < Build.VERSION_CODES.N; + boolean beforeP = targetSdk < Build.VERSION_CODES.P; + boolean beforeS = targetSdk < Build.VERSION_CODES.S; int smallHeight; boolean isCallLayout = contractedView instanceof CallLayout; boolean isMessagingLayout = contractedView instanceof MessagingLayout || contractedView instanceof ConversationLayout; + String summarization = null; + if (NotificationBundleUi.isEnabled()) { + summarization = mEntryAdapter.getSummarization(); + } else { + summarization = mEntry.getRanking().getSummarization(); + } + if (customView && beforeS && !mIsSummaryWithChildren) { if (beforeN) { smallHeight = mMaxSmallHeightBeforeN; @@ -876,7 +889,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView smallHeight = maxExpandedHeight; } else if (NmSummarizationUiFlag.isEnabled() && isMessagingLayout - && !TextUtils.isEmpty(mEntry.getRanking().getSummarization())) { + && !TextUtils.isEmpty(summarization)) { smallHeight = mMaxSmallHeightWithSummarization; } else { smallHeight = mMaxSmallHeight; @@ -910,6 +923,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mEntry; } + @Nullable + public EntryAdapter getEntryAdapter() { + NotificationBundleUi.assertInNewMode(); + return mEntryAdapter; + } + @Override public boolean isHeadsUp() { return mIsHeadsUp; @@ -1503,7 +1522,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public boolean hasFinishedInitialization() { - return getEntry().hasFinishedInitialization(); + if (NotificationBundleUi.isEnabled()) { + return initializationTime != -1 + && SystemClock.elapsedRealtime() > initializationTime + INITIALIZATION_DELAY; + } else { + return getEntry().hasFinishedInitialization(); + } + } + + public void resetInitializationTime() { + initializationTime = -1; + } + + public void setInitializationTime(long time) { + if (initializationTime == -1) { + initializationTime = time; + } } /** @@ -1518,7 +1552,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return null; } if (mMenuRow.getMenuView() == null) { - mMenuRow.createMenu(this, mEntry.getSbn()); + mMenuRow.createMenu(this); mMenuRow.setAppName(mAppName); FrameLayout.LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); @@ -1560,7 +1594,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (oldMenu != null) { int menuIndex = indexOfChild(oldMenu); removeView(oldMenu); - mMenuRow.createMenu(ExpandableNotificationRow.this, mEntry.getSbn()); + mMenuRow.createMenu(ExpandableNotificationRow.this); mMenuRow.setAppName(mAppName); addView(mMenuRow.getMenuView(), menuIndex); } @@ -1568,12 +1602,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView l.reinflate(); l.reInflateViews(); } - mEntry.getSbn().clearPackageContext(); + if (NotificationBundleUi.isEnabled()) { + mEntryAdapter.prepareForInflation(); + } else { + mEntry.getSbn().clearPackageContext(); + } // TODO: Move content inflation logic out of this call RowContentBindParams params = mRowContentBindStage.getStageParams(mEntry); params.setNeedsReinflation(true); - var rebindEndCallback = mRebindingTracker.trackRebinding(mEntry.getKey()); + var rebindEndCallback = mRebindingTracker.trackRebinding(NotificationBundleUi.isEnabled() + ? mEntryAdapter.getKey() : mEntry.getKey()); mRowContentBindStage.requestRebind(mEntry, (e) -> rebindEndCallback.onFinished()); Trace.endSection(); } @@ -1616,6 +1655,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (view != null) { view.setBackgroundTintColor(color); } + if (notificationRowTransparency() + && (mBackgroundNormal != null) + && (mEntry != null)) { + mBackgroundNormal.setBgIsColorized( + mEntry.getSbn().getNotification().isColorized()); + } } public void closeRemoteInput() { @@ -1631,20 +1676,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mPrivateLayout.setSingleLineWidthIndention(indention); } - public int getNotificationColor() { - return mNotificationColor; - } - - public void updateNotificationColor() { - Configuration currentConfig = getResources().getConfiguration(); - boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES; - - mNotificationColor = ContrastColorUtil.resolveContrastColor(mContext, - mEntry.getSbn().getNotification().color, - getBackgroundColorWithoutTint(), nightMode); - } - public HybridNotificationView getSingleLineView() { return mPrivateLayout.getSingleLineView(); } @@ -1902,15 +1933,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * Called when a notification which was previously kept in its parent for the * dismiss animation is finally detached from its parent. */ - void logKeepInParentChildDetached(NotificationEntry child, NotificationEntry oldParent); + void logKeepInParentChildDetached(String child, String oldParent); /** * Called when we want to attach a notification to a new parent, * but it still has the keepInParent flag set, so we skip it. */ void logSkipAttachingKeepInParentChild( - NotificationEntry child, - NotificationEntry newParent + String child, + String newParent ); /** @@ -1918,8 +1949,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * NotificationChildrenContainer */ void logRemoveTransientFromContainer( - NotificationEntry childEntry, - NotificationEntry containerEntry + String childEntry, + String containerEntry ); /** @@ -1927,7 +1958,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * NotificationStackScrollLayout */ void logRemoveTransientFromNssl( - NotificationEntry childEntry + String childEntry ); /** @@ -1935,7 +1966,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * is not NotificationChildrenContainer or NotificationStackScrollLayout */ void logRemoveTransientFromViewGroup( - NotificationEntry childEntry, + String childEntry, ViewGroup containerView ); @@ -1944,8 +1975,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * ExpandableNotificationRow */ void logAddTransientRow( - NotificationEntry childEntry, - NotificationEntry containerEntry, + String childEntry, + String containerEntry, int index ); @@ -1954,39 +1985,39 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * ExpandableNotificationRow */ void logRemoveTransientRow( - NotificationEntry childEntry, - NotificationEntry containerEntry + String childEntry, + String containerEntry ); /** * Called when resetting the alpha value for content views */ void logResetAllContentAlphas( - NotificationEntry entry + String entry ); /** * Called when resetting the alpha value for content views is skipped */ void logSkipResetAllContentAlphas( - NotificationEntry entry + String entry ); /** Called when we start an appear animation. */ - void logStartAppearAnimation(NotificationEntry entry, boolean isAppear); + void logStartAppearAnimation(String entry, boolean isAppear); /** Called when we cancel the running appear animation. */ - void logCancelAppearDrawing(NotificationEntry entry, boolean wasDrawing); + void logCancelAppearDrawing(String entry, boolean wasDrawing); /** Called when the animator of the appear animation is started. */ - void logAppearAnimationStarted(NotificationEntry entry, boolean isAppear); + void logAppearAnimationStarted(String entry, boolean isAppear); /** Called when we prepared an appear animation, but the animator was never started. */ - void logAppearAnimationSkipped(NotificationEntry entry, boolean isAppear); + void logAppearAnimationSkipped(String entry, boolean isAppear); /** Called when the animator of the appear animation is finished. */ void logAppearAnimationFinished( - NotificationEntry entry, + String entry, boolean isAppear, boolean cancelled ); @@ -2010,11 +2041,25 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * * @param context context context of the view * @param attrs attributes used to initialize parent view + * @param user the user the row is associated to + */ + public ExpandableNotificationRow(Context context, AttributeSet attrs, UserHandle user) { + this(context, attrs, userContextForEntry(context, user)); + NotificationBundleUi.assertInNewMode(); + } + + /** + * Constructs an ExpandableNotificationRow. Used by layout inflation (with a custom {@code + * AsyncLayoutFactory} in {@link RowInflaterTask}. + * + * @param context context context of the view + * @param attrs attributes used to initialize parent view * @param entry notification that the row will be associated to (determines the user for the * ImageResolver) */ public ExpandableNotificationRow(Context context, AttributeSet attrs, NotificationEntry entry) { this(context, attrs, userContextForEntry(context, entry)); + NotificationBundleUi.assertInLegacyMode(); } private static Context userContextForEntry(Context base, NotificationEntry entry) { @@ -2025,6 +2070,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView UserHandle.of(entry.getSbn().getNormalizedUserId()), /* flags= */ 0); } + private static Context userContextForEntry(Context base, UserHandle user) { + if (base.getUserId() == user.getIdentifier()) { + return base; + } + return base.createContextAsUser(user, /* flags= */ 0); + } + private ExpandableNotificationRow(Context sysUiContext, AttributeSet attrs, Context userContext) { super(sysUiContext, attrs); @@ -2044,7 +2096,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView NotificationEntry entry, RemoteInputViewSubcomponent.Factory rivSubcomponentFactory, String appName, - String notificationKey, + @NonNull String notificationKey, ExpandableNotificationRowLogger logger, KeyguardBypassController bypassController, GroupMembershipManager groupMembershipManager, @@ -2067,7 +2119,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView IStatusBarService statusBarService, UiEventLogger uiEventLogger, NotificationRebindingTracker notificationRebindingTracker) { - mEntry = entry; + + if (NotificationBundleUi.isEnabled()) { + // TODO (b/395857098): remove when all usages are migrated + mEntryAdapter = entry.getEntryAdapter(); + mEntry = entry; + } else { + mEntry = entry; + } mAppName = appName; mRebindingTracker = notificationRebindingTracker; if (mMenuRow == null) { @@ -2077,7 +2136,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mMenuRow.setAppName(mAppName); } mLogger = logger; - mLoggingKey = notificationKey; + mLoggingKey = logKey(notificationKey); mBypassController = bypassController; mGroupMembershipManager = groupMembershipManager; mGroupExpansionManager = groupExpansionManager; @@ -2205,6 +2264,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mEntry = entry; } + @VisibleForTesting + protected void setEntryAdapter(EntryAdapter entry) { + mEntryAdapter = entry; + } + private final Runnable mExpireRecentlyAlertedFlag = () -> applyAudiblyAlertedRecently(false); private void applyAudiblyAlertedRecently(boolean audiblyAlertedRecently) { @@ -2442,7 +2506,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mTranslateableViews.get(i).setTranslationX(0); } invalidateOutline(); - getEntry().getIcons().getShelfIcon().setScrollX(0); + getShelfIcon().setScrollX(0); } if (mMenuRow != null) { @@ -2561,7 +2625,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // In order to keep the shelf in sync with this swiping, we're simply translating // it's icon by the same amount. The translation is already being used for the normal // positioning, so we can use the scrollX instead. - getEntry().getIcons().getShelfIcon().setScrollX((int) -translationX); + getShelfIcon().setScrollX((int) -translationX); } if (mMenuRow != null && mMenuRow.getMenuView() != null) { @@ -2702,7 +2766,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView top = params.getTop(); } int actualHeight = params.getBottom() - top; - setActualHeight(actualHeight); + setFinalActualHeight(actualHeight); int notificationStackTop = params.getNotificationParentTop(); top -= notificationStackTop; @@ -2788,7 +2852,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public @NonNull StatusBarIconView getShelfIcon() { - return getEntry().getIcons().getShelfIcon(); + if (NotificationBundleUi.isEnabled()) { + return getEntryAdapter().getIcons().getShelfIcon(); + } else { + return mEntry.getIcons().getShelfIcon(); + } } @Override @@ -2876,8 +2944,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) { if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion && !mChildrenContainer.showingAsLowPriority()) { - final boolean wasExpanded = mGroupExpansionManager.isGroupExpanded(mEntry); - mGroupExpansionManager.setGroupExpanded(mEntry, userExpanded); + final boolean wasExpanded = isGroupExpanded(); + if (NotificationBundleUi.isEnabled()) { + mGroupExpansionManager.setGroupExpanded(mEntryAdapter, userExpanded); + } else { + mGroupExpansionManager.setGroupExpanded(mEntry, userExpanded); + } onExpansionChanged(true /* userAction */, wasExpanded); return; } @@ -3013,8 +3085,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * except for legacy use cases. */ public boolean canShowHeadsUp() { + boolean canEntryHun = NotificationBundleUi.isEnabled() + ? mEntryAdapter.canPeek() + : mEntry.isStickyAndNotDemoted(); if (mOnKeyguard && !isDozing() && !isBypassEnabled() && - (!mEntry.isStickyAndNotDemoted() + (!canEntryHun || (!mIgnoreLockscreenConstraints && mSaveSpaceOnLockscreen))) { return false; } @@ -3031,6 +3106,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public boolean isGroupExpanded() { + if (NotificationBundleUi.isEnabled()) { + return mGroupExpansionManager.isGroupExpanded(mEntryAdapter); + } return mGroupExpansionManager.isGroupExpanded(mEntry); } @@ -3050,7 +3128,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } if (!mIsSummaryWithChildren && wasSummary) { // Reset the 'when' once the row stops being a summary - mPublicLayout.setNotificationWhen(mEntry.getSbn().getNotification().getWhen()); + if (NotificationBundleUi.isEnabled()) { + mPublicLayout.setNotificationWhen(mEntryAdapter.getWhen()); + } else { + mPublicLayout.setNotificationWhen(mEntry.getSbn().getNotification().getWhen()); + } } getShowingLayout().updateBackgroundColor(false /* animate */); mPrivateLayout.updateExpandButtons(isExpandable()); @@ -3187,12 +3269,20 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public void setSensitive(boolean sensitive, boolean hideSensitive) { + if (notificationsRedesignTemplates() + && sensitive == mSensitive && hideSensitive == mSensitiveHiddenInGeneral) { + return; // nothing has changed + } + int intrinsicBefore = getIntrinsicHeight(); mSensitive = sensitive; mSensitiveHiddenInGeneral = hideSensitive; int intrinsicAfter = getIntrinsicHeight(); if (intrinsicBefore != intrinsicAfter) { notifyHeightChanged(/* needsAnimation= */ true); + } else if (notificationsRedesignTemplates()) { + // Just request the correct layout, even if the height hasn't changed + getShowingLayout().requestSelectLayout(/* needsAnimation= */ true); } } @@ -3246,7 +3336,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } resetAllContentAlphas(); } else { - mLogger.logSkipResetAllContentAlphas(getEntry()); + mLogger.logSkipResetAllContentAlphas(mLoggingKey); } mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE); updateChildrenVisibility(); @@ -3311,7 +3401,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView */ @Override public boolean canExpandableViewBeDismissed() { - if (areGutsExposed() || !mEntry.hasFinishedInitialization()) { + if (areGutsExposed() || !hasFinishedInitialization()) { return false; } return canViewBeDismissed(); @@ -3335,7 +3425,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView * clearability see {@link NotificationEntry#isClearable()}. */ public boolean canViewBeCleared() { - return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral); + if (NotificationBundleUi.isEnabled()) { + return mEntryAdapter.isClearable() + && (!shouldShowPublic() || !mSensitiveHiddenInGeneral); + } else { + return mEntry.isClearable() && (!shouldShowPublic() || !mSensitiveHiddenInGeneral); + } } private boolean shouldShowPublic() { @@ -3345,7 +3440,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void makeActionsVisibile() { setUserExpanded(true, true); if (isChildInGroup()) { - mGroupExpansionManager.setGroupExpanded(mEntry, true); + if (NotificationBundleUi.isEnabled()) { + mGroupExpansionManager.setGroupExpanded(mEntryAdapter, true); + } else { + mGroupExpansionManager.setGroupExpanded(mEntry, true); + } } notifyHeightChanged(/* needsAnimation= */ false); } @@ -3396,7 +3495,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public void performAddAnimation(long delay, long duration, boolean isHeadsUpAppear, Runnable onFinishRunnable) { - mLogger.logStartAppearAnimation(getEntry(), /* isAppear = */ true); + mLogger.logStartAppearAnimation(mLoggingKey, /* isAppear = */ true); super.performAddAnimation(delay, duration, isHeadsUpAppear, onFinishRunnable); } @@ -3409,7 +3508,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView Runnable onStartedRunnable, Runnable onFinishedRunnable, AnimatorListenerAdapter animationListener, ClipSide clipSide) { - mLogger.logStartAppearAnimation(getEntry(), /* isAppear = */ false); + mLogger.logStartAppearAnimation(mLoggingKey, /* isAppear = */ false); if (mMenuRow != null && mMenuRow.isMenuVisible()) { Animator anim = getTranslateViewAnimator(0f, null /* listener */); if (anim != null) { @@ -3439,20 +3538,20 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override protected void onAppearAnimationStarted(boolean isAppear) { - mLogger.logAppearAnimationStarted(getEntry(), /* isAppear = */ isAppear); + mLogger.logAppearAnimationStarted(mLoggingKey, /* isAppear = */ isAppear); super.onAppearAnimationStarted(isAppear); } @Override protected void onAppearAnimationSkipped(boolean isAppear) { - mLogger.logAppearAnimationSkipped(getEntry(), /* isAppear = */ isAppear); + mLogger.logAppearAnimationSkipped(mLoggingKey, /* isAppear = */ isAppear); super.onAppearAnimationSkipped(isAppear); } @Override protected void onAppearAnimationFinished(boolean wasAppearing, boolean cancelled) { mLogger.logAppearAnimationFinished( - /* entry = */ getEntry(), + /* entry = */ mLoggingKey, /* isAppear = */ wasAppearing, /* cancelled = */ cancelled ); @@ -3473,13 +3572,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public void cancelAppearDrawing() { - mLogger.logCancelAppearDrawing(getEntry(), isDrawingAppearAnimation()); + mLogger.logCancelAppearDrawing(mLoggingKey, isDrawingAppearAnimation()); super.cancelAppearDrawing(); } @Override public void resetAllContentAlphas() { - mLogger.logResetAllContentAlphas(getEntry()); + mLogger.logResetAllContentAlphas(mLoggingKey); mPrivateLayout.setAlpha(1f); mPrivateLayout.setLayerType(LAYER_TYPE_NONE, null); mPublicLayout.setAlpha(1f); @@ -3769,7 +3868,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void onExpandedByGesture(boolean userExpanded) { int event = MetricsEvent.ACTION_NOTIFICATION_GESTURE_EXPANDER; - if (mGroupMembershipManager.isGroupSummary(mEntry)) { + if (NotificationBundleUi.isEnabled() + ? mGroupMembershipManager.isGroupRoot(mEntryAdapter) + : mGroupMembershipManager.isGroupSummary(mEntry)) { event = MetricsEvent.ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER; } mMetricsLogger.action(event, userExpanded); @@ -3805,7 +3906,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private void onExpansionChanged(boolean userAction, boolean wasExpanded) { boolean nowExpanded = isExpanded(); if (mIsSummaryWithChildren && (!mIsMinimized || wasExpanded)) { - nowExpanded = mGroupExpansionManager.isGroupExpanded(mEntry); + nowExpanded = isGroupExpanded(); } // Note: nowExpanded is going to be true here on the first expansion of minimized groups, // even though the group itself is not expanded. Use mGroupExpansionManager to get the real @@ -4006,6 +4107,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } public boolean isMediaRow() { + NotificationBundleUi.assertInLegacyMode(); return mEntry.getSbn().getNotification().isMediaNotification(); } @@ -4128,7 +4230,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public void dump(PrintWriter pwOriginal, String[] args) { IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal); // Skip super call; dump viewState ourselves - pw.println("Notification: " + mEntry.getKey()); + if (NotificationBundleUi.isEnabled()) { + pw.println("Notification: " + mEntryAdapter.getKey()); + } else { + pw.println("Notification: " + mEntry.getKey()); + } DumpUtilsKt.withIncreasedIndent(pw, () -> { pw.println(this); pw.print("visibility: " + getVisibility()); @@ -4159,6 +4265,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView pw.print(", isPinned: " + isPinned()); pw.print(", expandedWhenPinned: " + mExpandedWhenPinned); pw.print(", isMinimized: " + mIsMinimized); + pw.print(", isAboveShelf: " + isAboveShelf()); pw.println(); if (NotificationContentView.INCLUDE_HEIGHTS_TO_DUMP) { @@ -4249,13 +4356,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private void logKeepInParentChildDetached(ExpandableNotificationRow child) { if (mLogger != null) { - mLogger.logKeepInParentChildDetached(child.getEntry(), getEntry()); + mLogger.logKeepInParentChildDetached(child.getLoggingKey(), mLoggingKey); } } private void logSkipAttachingKeepInParentChild(ExpandableNotificationRow child) { if (mLogger != null) { - mLogger.logSkipAttachingKeepInParentChild(child.getEntry(), getEntry()); + mLogger.logSkipAttachingKeepInParentChild(child.getLoggingKey(), mLoggingKey); } } @@ -4311,17 +4418,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } if (transientContainer instanceof NotificationChildrenContainer) { mLogger.logRemoveTransientFromContainer( - /* childEntry = */ getEntry(), + /* childEntry = */ mLoggingKey, /* containerEntry = */ ((NotificationChildrenContainer) transientContainer) - .getContainingNotification().getEntry() + .getContainingNotification().getLoggingKey() ); } else if (transientContainer instanceof NotificationStackScrollLayout) { mLogger.logRemoveTransientFromNssl( - /* childEntry = */ getEntry() + /* childEntry = */ mLoggingKey ); } else { mLogger.logRemoveTransientFromViewGroup( - /* childEntry = */ getEntry(), + /* childEntry = */ mLoggingKey, /* containerView = */ transientContainer ); } @@ -4339,7 +4446,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mLogger == null) { return; } - mLogger.logAddTransientRow(row.getEntry(), getEntry(), index); + mLogger.logAddTransientRow(row.getLoggingKey(), mLoggingKey, index); } @Override @@ -4354,6 +4461,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView if (mLogger == null) { return; } - mLogger.logRemoveTransientRow(row.getEntry(), getEntry()); + mLogger.logRemoveTransientRow(row.getLoggingKey(), mLoggingKey); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index 626230353bd7..07711b6e0eb8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -56,6 +56,7 @@ import com.android.systemui.statusbar.notification.people.PeopleNotificationIden import com.android.systemui.statusbar.notification.row.dagger.AppName; import com.android.systemui.statusbar.notification.row.dagger.NotificationKey; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.ui.view.NotificationRowStatsLogger; @@ -145,38 +146,38 @@ public class ExpandableNotificationRowController implements NotifViewController @Override public void logKeepInParentChildDetached( - NotificationEntry child, - NotificationEntry oldParent + String child, + String oldParent ) { mLogBufferLogger.logKeepInParentChildDetached(child, oldParent); } @Override public void logSkipAttachingKeepInParentChild( - NotificationEntry child, - NotificationEntry newParent + String child, + String newParent ) { mLogBufferLogger.logSkipAttachingKeepInParentChild(child, newParent); } @Override public void logRemoveTransientFromContainer( - NotificationEntry childEntry, - NotificationEntry containerEntry + String childEntry, + String containerEntry ) { mLogBufferLogger.logRemoveTransientFromContainer(childEntry, containerEntry); } @Override public void logRemoveTransientFromNssl( - NotificationEntry childEntry + String childEntry ) { mLogBufferLogger.logRemoveTransientFromNssl(childEntry); } @Override public void logRemoveTransientFromViewGroup( - NotificationEntry childEntry, + String childEntry, ViewGroup containerView ) { mLogBufferLogger.logRemoveTransientFromViewGroup(childEntry, containerView); @@ -184,8 +185,8 @@ public class ExpandableNotificationRowController implements NotifViewController @Override public void logAddTransientRow( - NotificationEntry childEntry, - NotificationEntry containerEntry, + String childEntry, + String containerEntry, int index ) { mLogBufferLogger.logAddTransientRow(childEntry, containerEntry, index); @@ -193,48 +194,48 @@ public class ExpandableNotificationRowController implements NotifViewController @Override public void logRemoveTransientRow( - NotificationEntry childEntry, - NotificationEntry containerEntry + String childEntry, + String containerEntry ) { mLogBufferLogger.logRemoveTransientRow(childEntry, containerEntry); } @Override public void logResetAllContentAlphas( - NotificationEntry entry + String entry ) { mLogBufferLogger.logResetAllContentAlphas(entry); } @Override public void logSkipResetAllContentAlphas( - NotificationEntry entry + String entry ) { mLogBufferLogger.logSkipResetAllContentAlphas(entry); } @Override - public void logStartAppearAnimation(NotificationEntry entry, boolean isAppear) { + public void logStartAppearAnimation(String entry, boolean isAppear) { mLogBufferLogger.logStartAppearAnimation(entry, isAppear); } @Override - public void logCancelAppearDrawing(NotificationEntry entry, boolean wasDrawing) { + public void logCancelAppearDrawing(String entry, boolean wasDrawing) { mLogBufferLogger.logCancelAppearDrawing(entry, wasDrawing); } @Override - public void logAppearAnimationStarted(NotificationEntry entry, boolean isAppear) { + public void logAppearAnimationStarted(String entry, boolean isAppear) { mLogBufferLogger.logAppearAnimationStarted(entry, isAppear); } @Override - public void logAppearAnimationSkipped(NotificationEntry entry, boolean isAppear) { + public void logAppearAnimationSkipped(String entry, boolean isAppear) { mLogBufferLogger.logAppearAnimationSkipped(entry, isAppear); } @Override - public void logAppearAnimationFinished(NotificationEntry entry, boolean isAppear, + public void logAppearAnimationFinished(String entry, boolean isAppear, boolean cancelled) { mLogBufferLogger.logAppearAnimationFinished(entry, isAppear, cancelled); } @@ -373,7 +374,11 @@ public class ExpandableNotificationRowController implements NotifViewController mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { - mView.getEntry().setInitializationTime(mClock.elapsedRealtime()); + if (NotificationBundleUi.isEnabled()) { + mView.setInitializationTime(mClock.elapsedRealtime()); + } else { + mView.getEntry().setInitializationTime(mClock.elapsedRealtime()); + } mPluginManager.addPluginListener(mView, NotificationMenuRowPlugin.class, false /* Allow multiple */); if (!SceneContainerFlag.isEnabled()) { @@ -405,7 +410,7 @@ public class ExpandableNotificationRowController implements NotifViewController @Override @NonNull public String getNodeLabel() { - return logKey(mView.getEntry()); + return NotificationBundleUi.isEnabled() ? mView.getLoggingKey() : logKey(mView.getEntry()); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index 2bc48746f847..da664f864f06 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.Flags.notificationColorUpdateLogger; +import static com.android.systemui.Flags.physicalNotificationMovement; import android.animation.AnimatorListenerAdapter; import android.content.Context; @@ -24,6 +25,7 @@ import android.content.res.Configuration; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.FloatProperty; import android.util.IndentingPrintWriter; import android.util.Log; import android.view.View; @@ -41,6 +43,7 @@ import com.android.app.animation.Interpolators; import com.android.systemui.Dumpable; import com.android.systemui.res.R; import com.android.systemui.statusbar.StatusBarIconView; +import com.android.systemui.statusbar.notification.PhysicsProperty; import com.android.systemui.statusbar.notification.Roundable; import com.android.systemui.statusbar.notification.RoundableState; import com.android.systemui.statusbar.notification.headsup.PinnedStatus; @@ -58,6 +61,20 @@ import java.util.List; * An abstract view for expandable views. */ public abstract class ExpandableView extends FrameLayout implements Dumpable, Roundable { + public static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag; + public static final PhysicsProperty HEIGHT_PROPERTY = new PhysicsProperty(TAG_ANIMATOR_HEIGHT, + new FloatProperty<>("ActualHeight") { + + @Override + public Float get(View view) { + return (float) ((ExpandableView) view).getActualHeight(); + } + + @Override + public void setValue(@NonNull View view, float value) { + ((ExpandableView) view).setActualHeight((int) value); + } + }); private static final String TAG = "ExpandableView"; /** whether the dump() for this class should include verbose details */ protected static final boolean DUMP_VERBOSE = Compile.IS_DEBUG @@ -84,7 +101,8 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro protected float mContentTransformationAmount; protected boolean mIsLastChild; protected int mContentShift; - @NonNull private final ExpandableViewState mViewState; + @NonNull + private final ExpandableViewState mViewState; private float mContentTranslation; protected boolean mLastInSection; protected boolean mFirstInSection; @@ -205,7 +223,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro MeasureSpec.EXACTLY); } child.measure(getChildMeasureSpec( - widthMeasureSpec, viewHorizontalPadding, layoutParams.width), + widthMeasureSpec, viewHorizontalPadding, layoutParams.width), childHeightSpec); int childHeight = child.getMeasuredHeight(); maxChildHeight = Math.max(maxChildHeight, childHeight); @@ -223,7 +241,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro // Now that we know our own height, measure the children that are MATCH_PARENT for (View child : mMatchParentViews) { child.measure(getChildMeasureSpec( - widthMeasureSpec, viewHorizontalPadding, child.getLayoutParams().width), + widthMeasureSpec, viewHorizontalPadding, child.getLayoutParams().width), exactlyOwnHeightSpec); } mMatchParentViews.clear(); @@ -269,12 +287,29 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro } /** + * Sets the final value of the actual height, which is to be applied immediately without + * animation. This may be different than the current value if we're animating away an offset. + */ + public void setFinalActualHeight(int childHeight) { + if (physicalNotificationMovement()) { + HEIGHT_PROPERTY.setFinalValue(this, childHeight); + } else { + setActualHeight(childHeight); + } + } + + /** + * Once the physical notification movement flag is enabled, don't use + * this directly as a public method since it may not update the property values and misbehave + * during animations. Use #setFinalActualHeight instead. + * * Sets the actual height of this notification. This is different than the laid out * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding. * - * @param actualHeight The height of this notification. + * @param actualHeight The height of this notification. * @param notifyListeners Whether the listener should be informed about the change. */ + @Deprecated public void setActualHeight(int actualHeight, boolean notifyListeners) { if (mActualHeight != actualHeight) { mActualHeight = actualHeight; @@ -285,7 +320,7 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro } } - public void setActualHeight(int actualHeight) { + protected void setActualHeight(int actualHeight) { setActualHeight(actualHeight, true /* notifyListeners */); } @@ -748,7 +783,8 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro * * @return the ExpandableView's view state. */ - @NonNull public ExpandableViewState getViewState() { + @NonNull + public ExpandableViewState getViewState() { return mViewState; } @@ -840,9 +876,10 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro * Set how much this notification is transformed into the shelf. * * @param contentTransformationAmount A value from 0 to 1 indicating how much we are transformed - * to the content away - * @param isLastChild is this the last child in the list. If true, then the transformation is - * different since its content fades out. + * to the content away + * @param isLastChild is this the last child in the list. If true, then the + * transformation is + * different since its content fades out. */ public void setContentTransformationAmount(float contentTransformationAmount, boolean isLastChild) { @@ -971,8 +1008,9 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable, Ro public interface OnHeightChangedListener { /** - * @param view the view for which the height changed, or {@code null} if just the top - * padding or the padding between the elements changed + * @param view the view for which the height changed, or {@code null} if just the + * top + * padding or the padding between the elements changed * @param needsAnimation whether the view height needs to be animated */ void onHeightChanged(ExpandableView view, boolean needsAnimation); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java index dd3a9c9dcf21..33c36d8c4c76 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.row; +import static com.android.systemui.Flags.notificationRowTransparency; import static com.android.systemui.util.ColorUtilKt.hexColorString; import android.content.Context; @@ -23,6 +24,7 @@ import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.Path; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -34,8 +36,10 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.graphics.ColorUtils; import com.android.internal.util.ContrastColorUtil; import com.android.systemui.Dumpable; +import com.android.systemui.common.shared.colors.SurfaceEffectColors; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss; import com.android.systemui.util.DrawableDumpKt; @@ -69,6 +73,7 @@ public class NotificationBackgroundView extends View implements Dumpable, private final ColorStateList mLightColoredStatefulColors; private final ColorStateList mDarkColoredStatefulColors; private final int mNormalColor; + private boolean mBgIsColorized = false; private final int convexR = 9; private final int concaveR = 22; @@ -82,8 +87,12 @@ public class NotificationBackgroundView extends View implements Dumpable, R.color.notification_state_color_light); mDarkColoredStatefulColors = getResources().getColorStateList( R.color.notification_state_color_dark); - mNormalColor = mContext.getColor( - com.android.internal.R.color.materialColorSurfaceContainerHigh); + if (notificationRowTransparency()) { + mNormalColor = SurfaceEffectColors.surfaceEffect1(getResources()); + } else { + mNormalColor = mContext.getColor( + com.android.internal.R.color.materialColorSurfaceContainerHigh); + } mFocusOverlayStroke = getResources().getDimension(R.dimen.notification_focus_stroke_width); } @@ -132,6 +141,21 @@ public class NotificationBackgroundView extends View implements Dumpable, } } + /** + * A way to tell whether the background has been colorized. + */ + public boolean isColorized() { + return mBgIsColorized; + } + + /** + * A way to inform this class whether the background has been colorized. + * We need to know this, in order to *not* override that color. + */ + public void setBgIsColorized(boolean b) { + mBgIsColorized = b; + } + private Path calculateDismissButtonCutoutPath(Rect backgroundBounds) { // TODO(b/365585705): Adapt to RTL after the UX design is finalized. @@ -280,7 +304,7 @@ public class NotificationBackgroundView extends View implements Dumpable, setCustomBackground(d); } - private Drawable getBaseBackgroundLayer() { + public Drawable getBaseBackgroundLayer() { return ((LayerDrawable) mBackground).getDrawable(0); } @@ -288,11 +312,27 @@ public class NotificationBackgroundView extends View implements Dumpable, return ((LayerDrawable) mBackground).getDrawable(1); } + private void updateBaseLayerColor() { + // BG base layer being a drawable, there isn't a method like setColor() to color it. + // Instead, we set a color filter that essentially replaces every pixel of the drawable. + // For non-colorized notifications, this function specifies a new color token. + // For colorized notifications, this uses a color that matches the tint color at 90% alpha. + getBaseBackgroundLayer().setColorFilter( + new PorterDuffColorFilter( + isColorized() + ? ColorUtils.setAlphaComponent(mTintColor, (int) (255 * 0.9f)) + : SurfaceEffectColors.surfaceEffect1(getResources()), + PorterDuff.Mode.SRC)); // SRC operator discards the drawable's color+alpha + } + public void setTint(int tintColor) { Drawable baseLayer = getBaseBackgroundLayer(); baseLayer.mutate().setTintMode(PorterDuff.Mode.SRC_ATOP); baseLayer.setTint(tintColor); mTintColor = tintColor; + if (notificationRowTransparency()) { + updateBaseLayerColor(); + } setStatefulColors(); invalidate(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index e311b53bfa64..c31f4ad5c3f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -56,6 +56,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.ConversationNotificationProcessor; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NmSummarizationUiFlag; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded; @@ -246,7 +247,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder entry.getRanking().getSummarization()); } else { result.mPublicInflatedSingleLineViewModel = - SingleLineViewInflater.inflateRedactedSingleLineViewModel( + SingleLineViewInflater.inflatePublicSingleLineViewModel( row.getContext(), isConversation ); @@ -508,7 +509,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder new Notification.Builder(packageContext, original.getChannelId()); redacted.setContentTitle(original.extras.getCharSequence(Notification.EXTRA_TITLE)); CharSequence redactedMessage = systemUiContext.getString( - R.string.redacted_notification_single_line_text + R.string.redacted_otp_notification_single_line_text ); redacted.setWhen(original.getWhen()); @@ -1361,7 +1362,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder ); } else { result.mPublicInflatedSingleLineViewModel = - SingleLineViewInflater.inflateRedactedSingleLineViewModel( + SingleLineViewInflater.inflatePublicSingleLineViewModel( mContext, isConversation ); @@ -1457,12 +1458,12 @@ public class NotificationContentInflater implements NotificationRowContentBinder } @Override - public void handleInflationException(NotificationEntry entry, Exception e) { + public void handleInflationException(Exception e) { handleError(e); } @Override - public void onAsyncInflationFinished(NotificationEntry entry) { + public void onAsyncInflationFinished() { mEntry.onInflationTaskFinished(); mRow.onNotificationUpdated(); if (mCallback != null) { 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 6e638f5de209..9a75253295d5 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 @@ -73,6 +73,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifGutsVi import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.row.icon.AppIconProvider; import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -436,7 +437,9 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta onNasFeedbackClick, mUiEventLogger, mDeviceProvisionedController.isDeviceProvisioned(), - row.getIsNonblockable(), + NotificationBundleUi.isEnabled() + ? !row.getEntry().isBlockable() + : row.getIsNonblockable(), mHighPriorityProvider.isHighPriority(row.getEntry()), mAssistantFeedbackController, mMetricsLogger, @@ -480,7 +483,9 @@ public class NotificationGutsManager implements NotifGutsViewManager, CoreStarta row.getEntry(), onSettingsClick, mDeviceProvisionedController.isDeviceProvisioned(), - row.getIsNonblockable()); + NotificationBundleUi.isEnabled() + ? !row.getEntry().isBlockable() + : row.getIsNonblockable()); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index b96b224a7d2e..ab382df13d10 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -186,7 +186,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl } @Override - public void createMenu(ViewGroup parent, StatusBarNotification sbn) { + public void createMenu(ViewGroup parent) { mParent = (ExpandableNotificationRow) parent; createMenuViews(true /* resetState */); } @@ -227,7 +227,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl } @Override - public void onNotificationUpdated(StatusBarNotification sbn) { + public void onNotificationUpdated() { if (mMenuContainer == null) { // Menu hasn't been created yet, no need to do anything. return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java index 0be1d5d9d79d..05934e7edfba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.lang.annotation.Retention; @@ -170,13 +171,29 @@ public interface NotificationRowContentBinder { * @param entry notification which failed to inflate content * @param e exception */ - void handleInflationException(NotificationEntry entry, Exception e); + default void handleInflationException(NotificationEntry entry, Exception e) { + handleInflationException(e); + } + + /** + * Callback for when there is an inflation exception + * + * @param e exception + */ + void handleInflationException(Exception e); /** * Callback for after the content views finish inflating. * * @param entry the entry with the content views set */ - void onAsyncInflationFinished(NotificationEntry entry); + default void onAsyncInflationFinished(NotificationEntry entry) { + onAsyncInflationFinished(); + } + + /** + * Callback for after the content views finish inflating. + */ + void onAsyncInflationFinished(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt index 517fc3a06d84..b9a3594a007e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt @@ -49,6 +49,7 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager import com.android.systemui.statusbar.notification.ConversationNotificationProcessor import com.android.systemui.statusbar.notification.InflationException import com.android.systemui.statusbar.notification.NmSummarizationUiFlag +import com.android.systemui.statusbar.notification.collection.EntryAdapter import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel @@ -76,6 +77,7 @@ import com.android.systemui.statusbar.notification.row.shared.NotificationConten import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer import com.android.systemui.statusbar.policy.InflatedSmartReplyState import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder @@ -536,7 +538,7 @@ constructor( val ident: String = (sbn.packageName + "/0x" + Integer.toHexString(sbn.id)) Log.e(TAG, "couldn't inflate view for notification $ident", e) callback?.handleInflationException( - row.entry, + if (NotificationBundleUi.isEnabled) entry else row.entry, InflationException("Couldn't inflate contentViews$e"), ) @@ -554,11 +556,11 @@ constructor( logger.logAsyncTaskProgress(entry, "aborted") } - override fun handleInflationException(entry: NotificationEntry, e: Exception) { + override fun handleInflationException(e: Exception) { handleError(e) } - override fun onAsyncInflationFinished(entry: NotificationEntry) { + override fun onAsyncInflationFinished() { this.entry.onInflationTaskFinished() row.onNotificationUpdated() callback?.onAsyncInflationFinished(this.entry) @@ -752,7 +754,7 @@ constructor( summarization = null, ) } else { - SingleLineViewInflater.inflateRedactedSingleLineViewModel( + SingleLineViewInflater.inflatePublicSingleLineViewModel( systemUiContext, entry.ranking.isConversation, ) @@ -790,7 +792,7 @@ constructor( val redacted = Notification.Builder(packageContext, original.channelId) redacted.setContentTitle(original.extras.getCharSequence(Notification.EXTRA_TITLE)) val redactedMessage = - sysUiContext.getString(R.string.redacted_notification_single_line_text) + sysUiContext.getString(R.string.redacted_otp_notification_single_line_text) if (originalStyle is MessagingStyle) { val newStyle = MessagingStyle(originalStyle.user) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt index 9e1c974a60ca..dad57a050c91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowLogger.kt @@ -22,8 +22,6 @@ import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel import com.android.systemui.log.dagger.NotificationLog import com.android.systemui.log.dagger.NotificationRenderLog -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.logKey import com.android.systemui.statusbar.notification.stack.MagneticNotificationRowManagerImpl import javax.inject.Inject @@ -33,60 +31,60 @@ constructor( @NotificationLog private val buffer: LogBuffer, @NotificationRenderLog private val notificationRenderBuffer: LogBuffer, ) { - fun logKeepInParentChildDetached(child: NotificationEntry, oldParent: NotificationEntry?) { + fun logKeepInParentChildDetached(child: String, oldParent: String?) { buffer.log( TAG, LogLevel.DEBUG, { - str1 = child.logKey - str2 = oldParent.logKey + str1 = child + str2 = oldParent }, { "Detach child $str1 kept in parent $str2" }, ) } - fun logSkipAttachingKeepInParentChild(child: NotificationEntry, newParent: NotificationEntry?) { + fun logSkipAttachingKeepInParentChild(child: String, newParent: String?) { buffer.log( TAG, LogLevel.WARNING, { - str1 = child.logKey - str2 = newParent.logKey + str1 = child + str2 = newParent }, { "Skipping to attach $str1 to $str2, because it still flagged to keep in parent" }, ) } fun logRemoveTransientFromContainer( - childEntry: NotificationEntry, - containerEntry: NotificationEntry, + childEntry: String, + containerEntry: String, ) { notificationRenderBuffer.log( TAG, LogLevel.INFO, { - str1 = childEntry.logKey - str2 = containerEntry.logKey + str1 = childEntry + str2 = containerEntry }, { "RemoveTransientRow from ChildrenContainer: childKey: $str1 -- containerKey: $str2" }, ) } - fun logRemoveTransientFromNssl(childEntry: NotificationEntry) { + fun logRemoveTransientFromNssl(childEntry: String) { notificationRenderBuffer.log( TAG, LogLevel.INFO, - { str1 = childEntry.logKey }, + { str1 = childEntry }, { "RemoveTransientRow from Nssl: childKey: $str1" }, ) } - fun logRemoveTransientFromViewGroup(childEntry: NotificationEntry, containerView: ViewGroup) { + fun logRemoveTransientFromViewGroup(childEntry: String, containerView: ViewGroup) { notificationRenderBuffer.log( TAG, LogLevel.WARNING, { - str1 = childEntry.logKey + str1 = childEntry str2 = containerView.toString() }, { "RemoveTransientRow from other ViewGroup: childKey: $str1 -- ViewGroup: $str2" }, @@ -94,94 +92,94 @@ constructor( } fun logAddTransientRow( - childEntry: NotificationEntry, - containerEntry: NotificationEntry, + childEntry: String, + containerEntry: String, index: Int, ) { notificationRenderBuffer.log( TAG, LogLevel.ERROR, { - str1 = childEntry.logKey - str2 = containerEntry.logKey + str1 = childEntry + str2 = containerEntry int1 = index }, { "addTransientRow to row: childKey: $str1 -- containerKey: $str2 -- index: $int1" }, ) } - fun logRemoveTransientRow(childEntry: NotificationEntry, containerEntry: NotificationEntry) { + fun logRemoveTransientRow(childEntry: String, containerEntry: String) { notificationRenderBuffer.log( TAG, LogLevel.ERROR, { - str1 = childEntry.logKey - str2 = containerEntry.logKey + str1 = childEntry + str2 = containerEntry }, { "removeTransientRow from row: childKey: $str1 -- containerKey: $str2" }, ) } - fun logResetAllContentAlphas(entry: NotificationEntry) { + fun logResetAllContentAlphas(entry: String) { notificationRenderBuffer.log( TAG, LogLevel.INFO, - { str1 = entry.logKey }, + { str1 = entry }, { "resetAllContentAlphas: $str1" }, ) } - fun logSkipResetAllContentAlphas(entry: NotificationEntry) { + fun logSkipResetAllContentAlphas(entry: String) { notificationRenderBuffer.log( TAG, LogLevel.INFO, - { str1 = entry.logKey }, + { str1 = entry }, { "Skip resetAllContentAlphas: $str1" }, ) } - fun logStartAppearAnimation(entry: NotificationEntry, isAppear: Boolean) { + fun logStartAppearAnimation(entry: String, isAppear: Boolean) { notificationRenderBuffer.log( TAG, LogLevel.DEBUG, { - str1 = entry.logKey + str1 = entry bool1 = isAppear }, { "startAppearAnimation childKey: $str1 isAppear:$bool1" }, ) } - fun logCancelAppearDrawing(entry: NotificationEntry, wasDrawing: Boolean) { + fun logCancelAppearDrawing(entry: String, wasDrawing: Boolean) { notificationRenderBuffer.log( TAG, LogLevel.WARNING, { - str1 = entry.logKey + str1 = entry bool1 = wasDrawing }, { "cancelAppearDrawing childKey: $str1 wasDrawing:$bool1" }, ) } - fun logAppearAnimationStarted(entry: NotificationEntry, isAppear: Boolean) { + fun logAppearAnimationStarted(entry: String, isAppear: Boolean) { notificationRenderBuffer.log( TAG, LogLevel.DEBUG, { - str1 = entry.logKey + str1 = entry bool1 = isAppear }, { "onAppearAnimationStarted childKey: $str1 isAppear:$bool1" }, ) } - fun logAppearAnimationSkipped(entry: NotificationEntry, isAppear: Boolean) { + fun logAppearAnimationSkipped(entry: String, isAppear: Boolean) { notificationRenderBuffer.log( TAG, LogLevel.WARNING, { - str1 = entry.logKey + str1 = entry bool1 = isAppear }, { "Skipped an appear animation childKey: $str1 isAppear:$bool1" }, @@ -189,7 +187,7 @@ constructor( } fun logAppearAnimationFinished( - entry: NotificationEntry, + entry: String, isAppear: Boolean, cancelled: Boolean, ) { @@ -197,7 +195,7 @@ constructor( TAG, LogLevel.DEBUG, { - str1 = entry.logKey + str1 = entry bool1 = isAppear bool2 = cancelled }, @@ -207,13 +205,13 @@ constructor( fun logMagneticAndRoundableTargetsNotSet( state: MagneticNotificationRowManagerImpl.State, - entry: NotificationEntry, + entry: String, ) { buffer.log( TAG, LogLevel.ERROR, { - str1 = entry.logKey + str1 = entry str2 = state.name }, { "Failed to set magnetic and roundable targets for $str1 on state $str2." }, @@ -222,13 +220,13 @@ constructor( fun logMagneticRowTranslationNotSet( state: MagneticNotificationRowManagerImpl.State, - entry: NotificationEntry, + entry: String, ) { buffer.log( TAG, LogLevel.ERROR, { - str1 = entry.logKey + str1 = entry str2 = state.name }, { "Failed to set magnetic row translation for $str1 on state $str2." }, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java index 6883ec575d7e..da361406fa2a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStage.java @@ -21,10 +21,12 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon import androidx.annotation.NonNull; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.statusbar.notification.collection.EntryAdapter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import javax.inject.Inject; @@ -52,7 +54,7 @@ public class RowContentBindStage extends BindStage<RowContentBindParams> { @Override protected void executeStage( - @NonNull NotificationEntry entry, + final @NonNull NotificationEntry entry, @NonNull ExpandableNotificationRow row, @NonNull StageCallback callback) { RowContentBindParams params = getStageParams(entry); @@ -77,15 +79,35 @@ public class RowContentBindStage extends BindStage<RowContentBindParams> { InflationCallback inflationCallback = new InflationCallback() { @Override - public void handleInflationException(NotificationEntry entry, Exception e) { - mNotifInflationErrorManager.setInflationError(entry, e); + public void handleInflationException(NotificationEntry errorEntry, Exception e) { + if (NotificationBundleUi.isEnabled()) { + mNotifInflationErrorManager.setInflationError(entry, e); + } else { + mNotifInflationErrorManager.setInflationError(errorEntry, e); + } + } + + @Override + public void handleInflationException(Exception e) { + } @Override - public void onAsyncInflationFinished(NotificationEntry entry) { - mNotifInflationErrorManager.clearInflationError(entry); - getStageParams(entry).clearDirtyContentViews(); - callback.onStageFinished(entry); + public void onAsyncInflationFinished(NotificationEntry finishedEntry) { + if (NotificationBundleUi.isEnabled()) { + mNotifInflationErrorManager.clearInflationError(entry); + getStageParams(entry).clearDirtyContentViews(); + callback.onStageFinished(entry); + } else { + mNotifInflationErrorManager.clearInflationError(finishedEntry); + getStageParams(finishedEntry).clearDirtyContentViews(); + callback.onStageFinished(finishedEntry); + } + } + + @Override + public void onAsyncInflationFinished() { + } }; mBinder.cancelBind(entry, row); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java index 9f634bef4c5e..3971661fa787 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.row; import android.content.Context; +import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -29,9 +30,12 @@ import androidx.annotation.VisibleForTesting; import androidx.asynclayoutinflater.view.AsyncLayoutFactory; import androidx.asynclayoutinflater.view.AsyncLayoutInflater; +import com.android.systemui.Flags; import com.android.systemui.res.R; +import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.util.time.SystemClock; import java.util.concurrent.Executor; @@ -41,7 +45,8 @@ import javax.inject.Inject; /** * An inflater task that asynchronously inflates a ExpandableNotificationRow */ -public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInflateFinishedListener { +public class RowInflaterTask implements InflationTask, + AsyncLayoutInflater.OnInflateFinishedListener, AsyncRowInflater.OnInflateFinishedListener { private static final String TAG = "RowInflaterTask"; private static final boolean TRACE_ORIGIN = true; @@ -52,12 +57,17 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf private Throwable mInflateOrigin; private final SystemClock mSystemClock; private final RowInflaterTaskLogger mLogger; + private final AsyncRowInflater mAsyncRowInflater; private long mInflateStartTimeMs; + private UserTracker mUserTracker; @Inject - public RowInflaterTask(SystemClock systemClock, RowInflaterTaskLogger logger) { + public RowInflaterTask(SystemClock systemClock, RowInflaterTaskLogger logger, + UserTracker userTracker, AsyncRowInflater asyncRowInflater) { mSystemClock = systemClock; mLogger = logger; + mUserTracker = userTracker; + mAsyncRowInflater = asyncRowInflater; } /** @@ -81,13 +91,19 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf mInflateOrigin = new Throwable("inflate requested here"); } mListener = listener; - AsyncLayoutInflater inflater = new AsyncLayoutInflater(context, makeRowInflater(entry)); + RowAsyncLayoutInflater asyncLayoutFactory = makeRowInflater(entry); mEntry = entry; entry.setInflationTask(this); mLogger.logInflateStart(entry); mInflateStartTimeMs = mSystemClock.elapsedRealtime(); - inflater.inflate(R.layout.status_bar_notification_row, parent, listenerExecutor, this); + if (Flags.useNotifInflationThreadForRow()) { + mAsyncRowInflater.inflate(context, asyncLayoutFactory, + R.layout.status_bar_notification_row, parent, this); + } else { + AsyncLayoutInflater inflater = new AsyncLayoutInflater(context, asyncLayoutFactory); + inflater.inflate(R.layout.status_bar_notification_row, parent, listenerExecutor, this); + } } /** @@ -107,40 +123,8 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf } private RowAsyncLayoutInflater makeRowInflater(NotificationEntry entry) { - return new RowAsyncLayoutInflater(entry, mSystemClock, mLogger); - } - - /** - * A {@link LayoutInflater} that is copy of BasicLayoutInflater. - */ - private static class BasicRowInflater extends LayoutInflater { - private static final String[] sClassPrefixList = - {"android.widget.", "android.webkit.", "android.app."}; - BasicRowInflater(Context context) { - super(context); - } - - @Override - public LayoutInflater cloneInContext(Context newContext) { - return new BasicRowInflater(newContext); - } - - @Override - protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException { - for (String prefix : sClassPrefixList) { - try { - View view = createView(name, prefix, attrs); - if (view != null) { - return view; - } - } catch (ClassNotFoundException e) { - // In this case we want to let the base class take a crack - // at it. - } - } - - return super.onCreateView(name, attrs); - } + return new RowAsyncLayoutInflater( + entry, mSystemClock, mLogger, mUserTracker.getUserHandle()); } @VisibleForTesting @@ -148,12 +132,14 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf private final NotificationEntry mEntry; private final SystemClock mSystemClock; private final RowInflaterTaskLogger mLogger; + private final UserHandle mTargetUser; public RowAsyncLayoutInflater(NotificationEntry entry, SystemClock systemClock, - RowInflaterTaskLogger logger) { + RowInflaterTaskLogger logger, UserHandle targetUser) { mEntry = entry; mSystemClock = systemClock; mLogger = logger; + mTargetUser = targetUser; } @Nullable @@ -165,8 +151,12 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf } final long startMs = mSystemClock.elapsedRealtime(); - final ExpandableNotificationRow row = - new ExpandableNotificationRow(context, attrs, mEntry); + ExpandableNotificationRow row = null; + if (NotificationBundleUi.isEnabled()) { + row = new ExpandableNotificationRow(context, attrs, mTargetUser); + } else { + row = new ExpandableNotificationRow(context, attrs, mEntry); + } final long elapsedMs = mSystemClock.elapsedRealtime() - startMs; mLogger.logCreatedRow(mEntry, elapsedMs); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt index b3c8f2219f4d..ea73b4ba8811 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt @@ -71,7 +71,7 @@ internal object SingleLineViewInflater { var contentText = if (redactText) { systemUiContext.getString( - com.android.systemui.res.R.string.redacted_notification_single_line_text + com.android.systemui.res.R.string.redacted_otp_notification_single_line_text ) } else { HybridGroupManager.resolveText(notification) @@ -120,7 +120,7 @@ internal object SingleLineViewInflater { } @JvmStatic - fun inflateRedactedSingleLineViewModel( + fun inflatePublicSingleLineViewModel( context: Context, isConversation: Boolean = false, ): SingleLineViewModel { @@ -144,7 +144,7 @@ internal object SingleLineViewInflater { com.android.systemui.res.R.string.redacted_notification_single_line_title ), context.getString( - com.android.systemui.res.R.string.redacted_notification_single_line_text + com.android.systemui.res.R.string.public_notification_single_line_text ), conversationData, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt index 9d13ab53ec71..6a96fba8f28d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt @@ -17,10 +17,12 @@ package com.android.systemui.statusbar.notification.row.wrapper import android.app.Flags +import android.app.Flags.notificationsRedesignTemplates import android.content.Context import android.graphics.drawable.AnimatedImageDrawable import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import com.android.internal.widget.CachingIconView import com.android.internal.widget.ConversationLayout import com.android.internal.widget.MessagingGroup @@ -53,8 +55,8 @@ class NotificationConversationTemplateViewWrapper( private lateinit var badgeIconView: NotificationRowIconView private lateinit var conversationBadgeBg: View private lateinit var expandBtn: View - private lateinit var expandBtnContainer: View - private lateinit var imageMessageContainer: ViewGroup + private var expandBtnContainer: View? = null + private var imageMessageContainer: ViewGroup? = null private lateinit var messageContainers: ArrayList<MessagingGroup> private lateinit var messagingLinearLayout: MessagingLinearLayout private lateinit var conversationTitleView: View @@ -78,10 +80,14 @@ class NotificationConversationTemplateViewWrapper( conversationBadgeBg = requireViewById(com.android.internal.R.id.conversation_icon_badge_bg) expandBtn = requireViewById(com.android.internal.R.id.expand_button) - expandBtnContainer = requireViewById(com.android.internal.R.id.expand_button_container) + expandBtnContainer = findViewById(com.android.internal.R.id.expand_button_container) importanceRing = requireViewById(com.android.internal.R.id.conversation_icon_badge_ring) appName = requireViewById(com.android.internal.R.id.app_name_text) - conversationTitleView = requireViewById(com.android.internal.R.id.conversation_text) + conversationTitleView = + requireViewById( + if (notificationsRedesignTemplates()) com.android.internal.R.id.title + else com.android.internal.R.id.conversation_text + ) facePileTop = findViewById(com.android.internal.R.id.conversation_face_pile_top) facePileBottom = findViewById(com.android.internal.R.id.conversation_face_pile_bottom) facePileBottomBg = @@ -133,11 +139,21 @@ class NotificationConversationTemplateViewWrapper( expandable: Boolean, onClickListener: View.OnClickListener, requestLayout: Boolean, - ) = conversationLayout.updateExpandability(expandable, onClickListener) + ) { + if (notificationsRedesignTemplates()) { + super.updateExpandability(expandable, onClickListener, requestLayout) + } else { + conversationLayout.updateExpandability(expandable, onClickListener) + } + } override fun disallowSingleClick(x: Float, y: Float): Boolean { val isOnExpandButton = - expandBtnContainer.visibility == View.VISIBLE && isOnView(expandBtnContainer, x, y) + if (notificationsRedesignTemplates()) { + expandBtn.isVisible && isOnView(expandBtn, x, y) + } else { + expandBtnContainer?.visibility == View.VISIBLE && isOnView(expandBtnContainer, x, y) + } return isOnExpandButton || super.disallowSingleClick(x, y) } @@ -158,7 +174,8 @@ class NotificationConversationTemplateViewWrapper( // and the top level image message container. val containers = messageContainers.asSequence().map { it.messageContainer } + - sequenceOf(imageMessageContainer) + if (notificationsRedesignTemplates()) emptySequence() + else sequenceOf(imageMessageContainer!!) val drawables = containers .flatMap { it.children } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java index 00b9aa42ab26..3d60092cf29a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AnimationProperties.java @@ -23,6 +23,8 @@ import android.util.Property; import android.view.View; import android.view.animation.Interpolator; +import androidx.dynamicanimation.animation.DynamicAnimation; + import java.util.function.Consumer; /** @@ -77,6 +79,34 @@ public class AnimationProperties { } /** + * @return a listener that will be added for a given property during its animation. Similar to + * the finish listener but used for Dynamic / SpringAnimations + */ + public DynamicAnimation.OnAnimationEndListener getAnimationEndListener(Property property) { + if (mAnimationEndAction == null && mAnimationCancelAction == null) { + return null; + } + Consumer<Property> cancelAction = mAnimationCancelAction; + Consumer<Property> endAction = mAnimationEndAction; + return (animation, canceled, value, velocity) -> { + if (canceled && cancelAction != null) { + cancelAction.accept(property); + } else if (!canceled && endAction != null) { + endAction.accept(property); + } + }; + } + + /** + * @return a listener that is invoked when a property animation starts, used for dynamic + * animations. For classical, interpolator based animations used the listeneradapter instead, + * this is only for Dynamic Animations + */ + public Consumer<DynamicAnimation> getAnimationStartListener(Property property) { + return null; + } + + /** * Add a callback for animation cancellation. */ public AnimationProperties setAnimationCancelAction(Consumer<Property> listener) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java index 69c9a4bf2dbb..8cf9dd365b60 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ExpandableViewState.java @@ -16,23 +16,31 @@ package com.android.systemui.statusbar.notification.stack; +import static com.android.systemui.Flags.physicalNotificationMovement; +import static com.android.systemui.statusbar.notification.row.ExpandableView.HEIGHT_PROPERTY; +import static com.android.systemui.statusbar.notification.row.ExpandableView.TAG_ANIMATOR_HEIGHT; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; +import android.util.FloatProperty; import android.view.View; +import androidx.annotation.NonNull; + import com.android.app.animation.Interpolators; import com.android.systemui.res.R; +import com.android.systemui.statusbar.notification.PhysicsProperty; +import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; /** -* A state of an expandable view -*/ + * A state of an expandable view + */ public class ExpandableViewState extends ViewState { - private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag; private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag; private static final int TAG_ANIMATOR_BOTTOM_INSET = R.id.bottom_inset_animator_tag; private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag; @@ -149,7 +157,7 @@ public class ExpandableViewState extends ViewState { // apply height if (height != newHeight) { - expandableView.setActualHeight(newHeight, false /* notifyListeners */); + expandableView.setFinalActualHeight(newHeight); } // apply hiding sensitive @@ -186,8 +194,24 @@ public class ExpandableViewState extends ViewState { // start height animation if (this.height != expandableView.getActualHeight()) { - startHeightAnimation(expandableView, properties); - } else { + if (mUsePhysicsForMovement) { + boolean animateHeight = properties.getAnimationFilter().animateHeight; + if (animateHeight) { + expandableView.setActualHeightAnimating(true); + } + PhysicsPropertyAnimator.setProperty(child, HEIGHT_PROPERTY, this.height, properties, + animateHeight, + (animation, canceled, value, velocity) -> { + expandableView.setActualHeightAnimating(false); + if (!canceled && child instanceof ExpandableNotificationRow) { + ((ExpandableNotificationRow) child).setGroupExpansionChanging( + false /* isExpansionChanging */); + } + }); + } else { + startHeightAnimationInterpolator(expandableView, properties); + } + } else { abortAnimation(child, TAG_ANIMATOR_HEIGHT); } @@ -224,7 +248,8 @@ public class ExpandableViewState extends ViewState { } } - private void startHeightAnimation(final ExpandableView child, AnimationProperties properties) { + private void startHeightAnimationInterpolator(final ExpandableView child, + AnimationProperties properties) { Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT); Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT); int newEndValue = this.height; @@ -374,38 +399,16 @@ public class ExpandableViewState extends ViewState { } }); startAnimator(animator, listener); - child.setTag(clipTop ? TAG_ANIMATOR_TOP_INSET:TAG_ANIMATOR_BOTTOM_INSET, animator); - child.setTag(clipTop ? TAG_START_TOP_INSET: TAG_START_BOTTOM_INSET, + child.setTag(clipTop ? TAG_ANIMATOR_TOP_INSET : TAG_ANIMATOR_BOTTOM_INSET, animator); + child.setTag(clipTop ? TAG_START_TOP_INSET : TAG_START_BOTTOM_INSET, clipTop ? child.getClipTopAmount() : child.getClipBottomAmount()); - child.setTag(clipTop ? TAG_END_TOP_INSET: TAG_END_BOTTOM_INSET, newEndValue); - } - - /** - * Get the end value of the height animation running on a view or the actualHeight - * if no animation is running. - */ - public static int getFinalActualHeight(ExpandableView view) { - if (view == null) { - return 0; - } - ValueAnimator heightAnimator = getChildTag(view, TAG_ANIMATOR_HEIGHT); - if (heightAnimator == null) { - return view.getActualHeight(); - } else { - return getChildTag(view, TAG_END_HEIGHT); - } + child.setTag(clipTop ? TAG_END_TOP_INSET : TAG_END_BOTTOM_INSET, newEndValue); } @Override public void cancelAnimations(View view) { super.cancelAnimations(view); - Animator animator = getChildTag(view, TAG_ANIMATOR_HEIGHT); - if (animator != null) { - animator.cancel(); - } - animator = getChildTag(view, TAG_ANIMATOR_TOP_INSET); - if (animator != null) { - animator.cancel(); - } + abortAnimation(view, TAG_ANIMATOR_HEIGHT); + abortAnimation(view, TAG_ANIMATOR_TOP_INSET); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt index a507c4ceecd2..de4af37e8c0b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MagneticNotificationRowManagerImpl.kt @@ -73,7 +73,7 @@ constructor( updateMagneticAndRoundableTargets(swipingRow, stackScrollLayout, sectionsManager) currentState = State.TARGETS_SET } else { - logger.logMagneticAndRoundableTargetsNotSet(currentState, swipingRow.entry) + logger.logMagneticAndRoundableTargetsNotSet(currentState, swipingRow.loggingKey) } } @@ -95,12 +95,15 @@ constructor( notificationTargetsHelper.findMagneticTargets( expandableNotificationRow, stackScrollLayout, + sectionsManager, MAGNETIC_TRANSLATION_MULTIPLIERS.size, ) - currentMagneticListeners.swipedListener()?.cancelTranslationAnimations() newListeners.forEach { if (currentMagneticListeners.contains(it)) { it?.cancelMagneticAnimations() + if (it == currentMagneticListeners.swipedListener()) { + it?.cancelTranslationAnimations() + } } } currentMagneticListeners = newListeners @@ -116,7 +119,7 @@ constructor( currentMagneticListeners.swipedListener()?.canRowBeDismissed() ?: false when (currentState) { State.IDLE -> { - logger.logMagneticRowTranslationNotSet(currentState, row.entry) + logger.logMagneticRowTranslationNotSet(currentState, row.getLoggingKey()) return false } State.TARGETS_SET -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index ee57d459e71c..1d185356626b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -1352,10 +1352,11 @@ public class NotificationChildrenContainer extends ViewGroup if (i < maxAllowedVisibleChildren) { float singleLineHeight = child.getShowingLayout().getMinHeight( false /* likeGroupExpanded */); - child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight, - childHeight, fraction), false); + childHeight = NotificationUtils.interpolate(singleLineHeight, + childHeight, fraction); + child.setFinalActualHeight((int) childHeight); } else { - child.setActualHeight((int) childHeight, false); + child.setFinalActualHeight((int) childHeight); } } } 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 b9352bf64be4..3ff18efeae53 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 @@ -26,6 +26,7 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_ import static com.android.internal.jank.InteractionJankMonitor.CUJ_SHADE_CLEAR_ALL; import static com.android.systemui.Flags.magneticNotificationSwipes; import static com.android.systemui.Flags.notificationOverExpansionClippingFix; +import static com.android.systemui.Flags.physicalNotificationMovement; import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT; import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE; import static com.android.systemui.statusbar.notification.stack.shared.model.AccessibilityScrollEvent.SCROLL_DOWN; @@ -109,6 +110,7 @@ import com.android.systemui.statusbar.notification.FakeShadowView; import com.android.systemui.statusbar.notification.LaunchAnimationParameters; import com.android.systemui.statusbar.notification.NotificationTransitionAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; +import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator; 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; @@ -122,6 +124,7 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization; import com.android.systemui.statusbar.notification.shared.NotificationHeadsUpCycling; import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun; @@ -2958,9 +2961,13 @@ public class NotificationStackScrollLayout } private boolean isChildInGroup(View child) { - return child instanceof ExpandableNotificationRow - && mGroupMembershipManager.isChildInGroup( - ((ExpandableNotificationRow) child).getEntry()); + if (child instanceof ExpandableNotificationRow) { + ExpandableNotificationRow childRow = (ExpandableNotificationRow) child; + return NotificationBundleUi.isEnabled() + ? mGroupMembershipManager.isChildInGroup(childRow.getEntryAdapter()) + : mGroupMembershipManager.isChildInGroup(childRow.getEntry()); + } + return false; } /** @@ -3639,6 +3646,9 @@ public class NotificationStackScrollLayout mScrollViewFields.sendCurrentGestureInGuts(false); mScrollViewFields.sendCurrentGestureOverscroll(false); setIsBeingDragged(false); + // dispatch to touchHandlers, so they can still finalize a previously started + // motion, while the shade is being dragged + return super.dispatchTouchEvent(ev); } return false; } @@ -5753,7 +5763,12 @@ public class NotificationStackScrollLayout + view.getActualHeight() - mShelf.getIntrinsicHeight(); } } else if (!firstVisibleView) { - view.setTranslationY(wakeUplocation); + if (physicalNotificationMovement()) { + PhysicsPropertyAnimator.setProperty(view, PhysicsPropertyAnimator.Y_TRANSLATION, + wakeUplocation); + } else { + view.setTranslationY(wakeUplocation); + } } } } @@ -6671,7 +6686,7 @@ public class NotificationStackScrollLayout static boolean canChildBeCleared(View v) { if (v instanceof ExpandableNotificationRow row) { - if (row.areGutsExposed() || !row.getEntry().hasFinishedInitialization()) { + if (row.areGutsExposed() || !row.hasFinishedInitialization()) { return false; } return row.canViewBeCleared(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt index b69b936ea9f0..8d7b2209ac43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationTargetsHelper.kt @@ -5,7 +5,6 @@ import androidx.core.view.isVisible import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.NotificationShelf import com.android.systemui.statusbar.notification.Roundable -import com.android.systemui.statusbar.notification.footer.ui.view.FooterView import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView import javax.inject.Inject @@ -88,6 +87,7 @@ class NotificationTargetsHelper @Inject constructor() { * * @param[viewSwiped] The [ExpandableNotificationRow] that is swiped. * @param[stackScrollLayout] [NotificationStackScrollLayout] container. + * @param[sectionsManager] The [NotificationSectionsManager] * @param[totalMagneticTargets] The total number of magnetic listeners in the resulting list. * This includes the listener of the view swiped. * @return The list of [MagneticRowListener]s above and below the swiped @@ -96,6 +96,7 @@ class NotificationTargetsHelper @Inject constructor() { fun findMagneticTargets( viewSwiped: ExpandableNotificationRow, stackScrollLayout: NotificationStackScrollLayout, + sectionsManager: NotificationSectionsManager, totalMagneticTargets: Int, ): List<MagneticRowListener?> { val notificationParent = viewSwiped.notificationParent @@ -126,26 +127,34 @@ class NotificationTargetsHelper @Inject constructor() { var canMoveRight = true for (distance in 1..totalMagneticTargets / 2) { if (canMoveLeft) { - val leftElement = container.getOrNull(index = centerIndex - distance) + val leftElement = + container.getOrNull(index = centerIndex - distance)?.takeIf { + it.isValidMagneticBoundary() || + !sectionsManager.beginsSection(view = viewSwiped, previous = it) + } if (leftElement is ExpandableNotificationRow) { magneticTargets[leftIndex] = leftElement.magneticRowListener leftIndex-- } else { if (leftElement.isValidMagneticBoundary()) { - // Add the boundary and then stop the iterating + // Add the boundary and then stop iterating magneticTargets[leftIndex] = leftElement?.magneticRowListener } canMoveLeft = false } } if (canMoveRight) { - val rightElement = container.getOrNull(index = centerIndex + distance) + val rightElement = + container.getOrNull(index = centerIndex + distance)?.takeIf { + it.isValidMagneticBoundary() || + !sectionsManager.beginsSection(view = it, previous = viewSwiped) + } if (rightElement is ExpandableNotificationRow) { magneticTargets[rightIndex] = rightElement.magneticRowListener rightIndex++ } else { if (rightElement.isValidMagneticBoundary()) { - // Add the boundary and then stop the iterating + // Add the boundary and then stop iterating magneticTargets[rightIndex] = rightElement?.magneticRowListener } canMoveRight = false @@ -157,7 +166,6 @@ class NotificationTargetsHelper @Inject constructor() { private fun ExpandableView?.isValidMagneticBoundary(): Boolean = when (this) { - is FooterView, is NotificationShelf, is SectionHeaderView -> true else -> false 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 06b989aaab57..08692bea2292 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 @@ -1227,13 +1227,17 @@ public class StackScrollAlgorithm { float baseZ = ambientState.getBaseZHeight(); if (SceneContainerFlag.isEnabled()) { - // SceneContainer flags off this logic, and just sets the baseZ because: + // SceneContainer simplifies this logic, because: // - there are no overlapping HUNs anymore, no need for multiplying their shadows // - shadows for HUNs overlapping with the stack are now set from updateHeadsUpStates - // - shadows for HUNs overlapping with the shelf are NOT set anymore, because it only - // happens on AOD/Pulsing, where they're displayed on a black background so a shadow - // wouldn't be visible. - childViewState.setZTranslation(baseZ); + if (child.isPinned() || ambientState.getTrackedHeadsUpRow() == child) { + // set a default elevation on the HUN, which would be overridden + // from updateHeadsUpStates if it is displayed in the shade + childViewState.setZTranslation(baseZ + mPinnedZTranslationExtra); + } else { + // set baseZ for every notification + childViewState.setZTranslation(baseZ); + } } else { if (child.mustStayOnScreen() && !childViewState.headsUpIsVisible && !ambientState.isDozingAndNotPulsing(child) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index c783250f2e0a..5e0d57ebb3fe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.stack; +import static com.android.systemui.Flags.physicalNotificationMovement; +import static com.android.systemui.statusbar.notification.row.ExpandableView.HEIGHT_PROPERTY; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_CYCLING_IN; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_HEADS_UP_CYCLING_OUT; @@ -29,11 +31,14 @@ import android.content.Context; import android.util.Property; import android.view.View; +import androidx.dynamicanimation.animation.DynamicAnimation; + import com.android.app.animation.Interpolators; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.res.R; import com.android.systemui.shared.clocks.AnimatableClockView; import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; @@ -41,6 +46,7 @@ import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import java.util.ArrayList; import java.util.HashSet; import java.util.Stack; +import java.util.function.Consumer; /** * An stack state animator which handles animations to new StackScrollStates @@ -68,8 +74,10 @@ public class StackStateAnimator { public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2; private static final int MAX_STAGGER_COUNT = 5; - @VisibleForTesting int mGoToFullShadeAppearingTranslation; - @VisibleForTesting float mHeadsUpAppearStartAboveScreen; + @VisibleForTesting + int mGoToFullShadeAppearingTranslation; + @VisibleForTesting + float mHeadsUpAppearStartAboveScreen; // Padding between the old and new heads up notifications for the hun cycling animation private float mHeadsUpCyclingPadding; private final ExpandableViewState mTmpState = new ExpandableViewState(); @@ -80,8 +88,9 @@ public class StackStateAnimator { private ArrayList<View> mNewAddChildren = new ArrayList<>(); private HashSet<View> mHeadsUpAppearChildren = new HashSet<>(); private HashSet<View> mHeadsUpDisappearChildren = new HashSet<>(); - private HashSet<Animator> mAnimatorSet = new HashSet<>(); + private HashSet<Object> mAnimatorSet = new HashSet<>(); private Stack<AnimatorListenerAdapter> mAnimationListenerPool = new Stack<>(); + private Stack<DynamicAnimation.OnAnimationEndListener> mAnimationEndPool = new Stack<>(); private AnimationFilter mAnimationFilter = new AnimationFilter(); private long mCurrentLength; private long mCurrentAdditionalDelay; @@ -99,6 +108,9 @@ public class StackStateAnimator { mHostLayout = hostLayout; initView(context); mAnimationProperties = new AnimationProperties() { + + private final Consumer<DynamicAnimation> mDynamicAnimationConsumer = mAnimatorSet::add; + @Override public AnimationFilter getAnimationFilter() { return mAnimationFilter; @@ -110,6 +122,17 @@ public class StackStateAnimator { } @Override + public DynamicAnimation.OnAnimationEndListener getAnimationEndListener( + Property property) { + return getGlobalAnimationEndListener(); + } + + @Override + public Consumer<DynamicAnimation> getAnimationStartListener(Property property) { + return mDynamicAnimationConsumer; + } + + @Override public boolean wasAdded(View view) { return mNewAddChildren.contains(view); } @@ -187,11 +210,11 @@ public class StackStateAnimator { adaptDurationWhenGoingToFullShade(child, viewState, wasAdded, animationStaggerCount); mAnimationProperties.delay = 0; if (wasAdded || mAnimationFilter.hasDelays - && (viewState.getYTranslation() != child.getTranslationY() - || viewState.getZTranslation() != child.getTranslationZ() - || viewState.getAlpha() != child.getAlpha() - || viewState.height != child.getActualHeight() - || viewState.clipTopAmount != child.getClipTopAmount())) { + && (viewState.getYTranslation() != child.getTranslationY() + || viewState.getZTranslation() != child.getTranslationZ() + || viewState.getAlpha() != child.getAlpha() + || viewState.height != child.getActualHeight() + || viewState.clipTopAmount != child.getClipTopAmount())) { mAnimationProperties.delay = mCurrentAdditionalDelay + calculateChildAnimationDelay(viewState, animationStaggerCount); } @@ -209,7 +232,13 @@ public class StackStateAnimator { mAnimationProperties.duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50 + (long) (100 * longerDurationFactor); } - child.setTranslationY(viewState.getYTranslation() + startOffset); + float newTranslationY = viewState.getYTranslation() + startOffset; + if (physicalNotificationMovement()) { + PhysicsPropertyAnimator.setProperty(child, PhysicsPropertyAnimator.Y_TRANSLATION, + newTranslationY); + } else { + child.setTranslationY(newTranslationY); + } } } @@ -312,7 +341,7 @@ public class StackStateAnimator { /** * @return an adapter which ensures that onAnimationFinished is called once no animation is - * running anymore + * running anymore */ private AnimatorListenerAdapter getGlobalAnimationFinishedListener() { if (!mAnimationListenerPool.empty()) { @@ -345,6 +374,27 @@ public class StackStateAnimator { }; } + /** + * @return an adapter which ensures that onAnimationFinished is called once no animation is + * running anymore + */ + private DynamicAnimation.OnAnimationEndListener getGlobalAnimationEndListener() { + if (!mAnimationEndPool.empty()) { + return mAnimationEndPool.pop(); + } + return new DynamicAnimation.OnAnimationEndListener() { + @Override + public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, + float velocity) { + mAnimatorSet.remove(animation); + if (mAnimatorSet.isEmpty() && !canceled) { + onAnimationFinished(); + } + mAnimationEndPool.push(this); + } + }; + } + private void onAnimationFinished() { mHostLayout.onChildAnimationFinished(); @@ -358,7 +408,7 @@ public class StackStateAnimator { * Process the animationEvents for a new animation. Here is the place to do something custom, * like to modify the ViewState or to create a custom animation for an event. * - * @param animationEvents the animation events for the animation to perform + * @param animationEvents the animation events for the animation to perform * @return true if any custom animation was created */ private boolean processAnimationEvents( @@ -428,7 +478,7 @@ public class StackStateAnimator { translationDirection = ((viewState.getYTranslation() - (ownPosition + actualHeight / 2.0f)) * 2 / actualHeight); - translationDirection = Math.max(Math.min(translationDirection, 1.0f),-1.0f); + translationDirection = Math.max(Math.min(translationDirection, 1.0f), -1.0f); } Runnable postAnimation; @@ -446,7 +496,7 @@ public class StackStateAnimator { changingView.removeFromTransientContainer(); }; } else { - startAnimation = ()-> { + startAnimation = () -> { changingView.setInRemovalAnimation(true); }; postAnimation = () -> { @@ -460,7 +510,7 @@ public class StackStateAnimator { ExpandableView.ClipSide.BOTTOM); needsCustomAnimation = true; } else if (event.animationType == - NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) { + NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT) { boolean isFullySwipedOut = mHostLayout.isFullySwipedOut(changingView); if (loggable) { mLogger.processAnimationEventsRemoveSwipeOut(key, isFullySwipedOut, isHeadsUp); @@ -699,8 +749,8 @@ public class StackStateAnimator { /** * @param headsUpFromBottom Whether we are showing the HUNs at the bottom of the screen - * @param oldHunHeight Height of the old HUN - * @param newHunHeight Height of the new HUN + * @param oldHunHeight Height of the old HUN + * @param newHunHeight Height of the new HUN * @return The y translation target value of the HUN cycling out animation */ private float getHeadsUpCyclingOutYTranslation( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java index b2ffa4aa8233..2ef6f362af34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java @@ -16,6 +16,10 @@ package com.android.systemui.statusbar.notification.stack; +import static com.android.systemui.Flags.physicalNotificationMovement; +import static com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.TAG_ANIMATOR_TRANSLATION_Y; +import static com.android.systemui.statusbar.notification.PhysicsPropertyAnimator.Y_TRANSLATION; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -26,14 +30,20 @@ import android.util.Property; import android.view.View; import android.view.animation.Interpolator; +import androidx.dynamicanimation.animation.DynamicAnimation; +import androidx.dynamicanimation.animation.SpringAnimation; + import com.android.app.animation.Interpolators; import com.android.systemui.Dumpable; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.AnimatableProperty; import com.android.systemui.statusbar.notification.NotificationFadeAware.FadeOptimizedNotification; +import com.android.systemui.statusbar.notification.PhysicsProperty; +import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator; import com.android.systemui.statusbar.notification.PropertyAnimator; -import com.android.systemui.statusbar.notification.row.ExpandableView; +import com.android.systemui.statusbar.notification.PropertyData; import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil; +import com.android.systemui.statusbar.notification.row.ExpandableView; import java.io.PrintWriter; import java.lang.reflect.Field; @@ -46,6 +56,14 @@ import java.lang.reflect.Modifier; */ public class ViewState implements Dumpable { + public ViewState() { + this(physicalNotificationMovement()); + } + + public ViewState(boolean usePhysicsForMovement) { + setUsePhysicsForMovement(usePhysicsForMovement); + } + /** * Some animation properties that can be used to update running animations but not creating * any new ones. @@ -59,7 +77,6 @@ public class ViewState implements Dumpable { } }; private static final int TAG_ANIMATOR_TRANSLATION_X = R.id.translation_x_animator_tag; - private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag; private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag; private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag; private static final int TAG_END_TRANSLATION_X = R.id.translation_x_animator_end_value_tag; @@ -72,8 +89,7 @@ public class ViewState implements Dumpable { private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag; private static final String LOG_TAG = "StackViewState"; - private static final AnimatableProperty SCALE_X_PROPERTY - = new AnimatableProperty() { + private static final AnimatableProperty SCALE_X_PROPERTY = new AnimatableProperty() { @Override public int getAnimationStartTag() { @@ -96,8 +112,7 @@ public class ViewState implements Dumpable { } }; - private static final AnimatableProperty SCALE_Y_PROPERTY - = new AnimatableProperty() { + private static final AnimatableProperty SCALE_Y_PROPERTY = new AnimatableProperty() { @Override public int getAnimationStartTag() { @@ -129,11 +144,16 @@ public class ViewState implements Dumpable { private float mZTranslation; private float mScaleX = 1.0f; private float mScaleY = 1.0f; + protected boolean mUsePhysicsForMovement = false; public float getAlpha() { return mAlpha; } + public void setUsePhysicsForMovement(boolean usePhysicsForMovement) { + this.mUsePhysicsForMovement = usePhysicsForMovement; + } + /** * @param alpha View transparency. */ @@ -230,6 +250,7 @@ public class ViewState implements Dumpable { hidden = viewState.hidden; mScaleX = viewState.mScaleX; mScaleY = viewState.mScaleY; + mUsePhysicsForMovement = viewState.mUsePhysicsForMovement; } public void initFrom(View view) { @@ -261,11 +282,15 @@ public class ViewState implements Dumpable { } // apply yTranslation - boolean animatingY = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Y); - if (animatingY) { - updateAnimationY(view); - } else if (view.getTranslationY() != this.mYTranslation) { - view.setTranslationY(this.mYTranslation); + if (mUsePhysicsForMovement) { + PhysicsPropertyAnimator.setProperty(view, Y_TRANSLATION, this.mYTranslation); + } else { + boolean animatingY = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Y); + if (animatingY) { + updateAnimationY(view); + } else if (view.getTranslationY() != this.mYTranslation) { + view.setTranslationY(this.mYTranslation); + } } // apply zTranslation @@ -293,8 +318,8 @@ public class ViewState implements Dumpable { } int oldVisibility = view.getVisibility(); - boolean becomesInvisible = this.mAlpha == 0.0f - || (this.hidden && (!isAnimating(view) || oldVisibility != View.VISIBLE)); + boolean becomesInvisible = this.mAlpha == 0.0f || (this.hidden && (!isAnimating(view) + || oldVisibility != View.VISIBLE)); boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA); if (animatingAlpha) { updateAlphaAnimation(view); @@ -315,9 +340,8 @@ public class ViewState implements Dumpable { } else { boolean newLayerTypeIsHardware = becomesFaded && view.hasOverlappingRendering(); int layerType = view.getLayerType(); - int newLayerType = newLayerTypeIsHardware - ? View.LAYER_TYPE_HARDWARE - : View.LAYER_TYPE_NONE; + int newLayerType = + newLayerTypeIsHardware ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE; if (layerType != newLayerType) { view.setLayerType(newLayerType, null); } @@ -360,11 +384,19 @@ public class ViewState implements Dumpable { } private static boolean isAnimating(View view, int tag) { - return getChildTag(view, tag) != null; + Object childTag = getChildTag(view, tag); + if (childTag instanceof PropertyData propertyData) { + return propertyData.getAnimator() != null; + } + return childTag != null; } public static boolean isAnimating(View view, AnimatableProperty property) { - return getChildTag(view, property.getAnimatorTag()) != null; + Object childTag = getChildTag(view, property.getAnimatorTag()); + if (childTag instanceof PropertyData propertyData) { + return propertyData.getAnimator() != null; + } + return childTag != null; } /** @@ -376,8 +408,7 @@ public class ViewState implements Dumpable { public void animateTo(View child, AnimationProperties animationProperties) { boolean wasVisible = child.getVisibility() == View.VISIBLE; final float alpha = this.mAlpha; - if (!wasVisible && (alpha != 0 || child.getAlpha() != 0) - && !this.gone && !this.hidden) { + if (!wasVisible && (alpha != 0 || child.getAlpha() != 0) && !this.gone && !this.hidden) { child.setVisibility(View.VISIBLE); } float childAlpha = child.getAlpha(); @@ -465,8 +496,8 @@ public class ViewState implements Dumpable { } } - ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA, - child.getAlpha(), newEndValue); + ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA, child.getAlpha(), + newEndValue); animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); // Handle layer type child.setLayerType(View.LAYER_TYPE_HARDWARE, null); @@ -516,8 +547,7 @@ public class ViewState implements Dumpable { startZTranslationAnimation(view, NO_NEW_ANIMATIONS); } - private void updateAnimation(View view, AnimatableProperty property, - float endValue) { + private void updateAnimation(View view, AnimatableProperty property, float endValue) { PropertyAnimator.startAnimation(view, property, endValue, NO_NEW_ANIMATIONS); } @@ -615,8 +645,8 @@ public class ViewState implements Dumpable { child.getTranslationX(), newEndValue); Interpolator customInterpolator = properties.getCustomInterpolator(child, View.TRANSLATION_X); - Interpolator interpolator = customInterpolator != null ? customInterpolator - : Interpolators.FAST_OUT_SLOW_IN; + Interpolator interpolator = + customInterpolator != null ? customInterpolator : Interpolators.FAST_OUT_SLOW_IN; animator.setInterpolator(interpolator); long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator); animator.setDuration(newDuration); @@ -649,6 +679,24 @@ public class ViewState implements Dumpable { } private void startYTranslationAnimation(final View child, AnimationProperties properties) { + if (mUsePhysicsForMovement) { + // Y Translation does some extra calls when it ends, so lets add a listener + DynamicAnimation.OnAnimationEndListener endListener = + (animation, canceled, value, velocity) -> { + if (!canceled) { + HeadsUpUtil.setNeedsHeadsUpDisappearAnimationAfterClick(child, false); + onYTranslationAnimationFinished(child); + } + }; + PhysicsPropertyAnimator.setProperty(child, Y_TRANSLATION, this.mYTranslation, + properties, properties.getAnimationFilter().animateY, endListener); + } else { + startYTranslationInterpolatorAnimation(child, properties); + } + } + + private void startYTranslationInterpolatorAnimation(View child, + AnimationProperties properties) { Float previousStartValue = getChildTag(child, TAG_START_TRANSLATION_Y); Float previousEndValue = getChildTag(child, TAG_END_TRANSLATION_Y); float newEndValue = this.mYTranslation; @@ -681,8 +729,8 @@ public class ViewState implements Dumpable { child.getTranslationY(), newEndValue); Interpolator customInterpolator = properties.getCustomInterpolator(child, View.TRANSLATION_Y); - Interpolator interpolator = customInterpolator != null ? customInterpolator - : Interpolators.FAST_OUT_SLOW_IN; + Interpolator interpolator = + customInterpolator != null ? customInterpolator : Interpolators.FAST_OUT_SLOW_IN; animator.setInterpolator(interpolator); long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator); animator.setDuration(newDuration); @@ -731,9 +779,19 @@ public class ViewState implements Dumpable { } protected void abortAnimation(View child, int animatorTag) { - Animator previousAnimator = getChildTag(child, animatorTag); - if (previousAnimator != null) { - previousAnimator.cancel(); + Object storedTag = getChildTag(child, animatorTag); + if (storedTag != null) { + if (storedTag instanceof Animator animator) { + animator.cancel(); + } else if (storedTag instanceof PropertyData propertyData) { + // Physics based animation! + Runnable delayRunnable = propertyData.getDelayRunnable(); + child.removeCallbacks(delayRunnable); + SpringAnimation animator = propertyData.getAnimator(); + if (animator != null) { + animator.cancel(); + } + } } } @@ -750,46 +808,15 @@ public class ViewState implements Dumpable { if (previousAnimator != null) { // We take either the desired length of the new animation or the remaining time of // the previous animator, whichever is longer. - newDuration = Math.max(previousAnimator.getDuration() - - previousAnimator.getCurrentPlayTime(), newDuration); + newDuration = Math.max( + previousAnimator.getDuration() - previousAnimator.getCurrentPlayTime(), + newDuration); previousAnimator.cancel(); } return newDuration; } /** - * Get the end value of the xTranslation animation running on a view or the xTranslation - * if no animation is running. - */ - public static float getFinalTranslationX(View view) { - if (view == null) { - return 0; - } - ValueAnimator xAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_X); - if (xAnimator == null) { - return view.getTranslationX(); - } else { - return getChildTag(view, TAG_END_TRANSLATION_X); - } - } - - /** - * Get the end value of the yTranslation animation running on a view or the yTranslation - * if no animation is running. - */ - public static float getFinalTranslationY(View view) { - if (view == null) { - return 0; - } - ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y); - if (yAnimator == null) { - return view.getTranslationY(); - } else { - return getChildTag(view, TAG_END_TRANSLATION_Y); - } - } - - /** * Get the end value of the zTranslation animation running on a view or the zTranslation * if no animation is running. */ @@ -806,26 +833,14 @@ public class ViewState implements Dumpable { } public static boolean isAnimatingY(View child) { - return getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null; + return isAnimating(child, TAG_ANIMATOR_TRANSLATION_Y); } public void cancelAnimations(View view) { - Animator animator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_X); - if (animator != null) { - animator.cancel(); - } - animator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y); - if (animator != null) { - animator.cancel(); - } - animator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Z); - if (animator != null) { - animator.cancel(); - } - animator = getChildTag(view, TAG_ANIMATOR_ALPHA); - if (animator != null) { - animator.cancel(); - } + abortAnimation(view, TAG_ANIMATOR_TRANSLATION_X); + abortAnimation(view, TAG_ANIMATOR_TRANSLATION_Y); + abortAnimation(view, TAG_ANIMATOR_TRANSLATION_Z); + abortAnimation(view, TAG_ANIMATOR_ALPHA); } @Override @@ -840,8 +855,8 @@ public class ViewState implements Dumpable { // Print field names paired with their values for (Field field : fields) { int modifiers = field.getModifiers(); - if (Modifier.isStatic(modifiers) || field.isSynthetic() - || Modifier.isTransient(modifiers)) { + if (Modifier.isStatic(modifiers) || field.isSynthetic() || Modifier.isTransient( + modifiers)) { continue; } if (!first) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/ShadeScrimBounds.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/ShadeScrimBounds.kt index 832e69080f3c..78ece5336d04 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/ShadeScrimBounds.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/model/ShadeScrimBounds.kt @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.stack.shared.model +import androidx.compose.ui.geometry.Rect + /** Models the bounds of the notification stack. */ data class ShadeScrimBounds( /** The position of the left of the stack in its window coordinate system, in pixels. */ @@ -27,6 +29,10 @@ data class ShadeScrimBounds( /** The position of the bottom of the stack in its window coordinate system, in pixels. */ val bottom: Float = 0f, ) { + constructor( + bounds: Rect + ) : this(left = bounds.left, top = bounds.top, right = bounds.right, bottom = bounds.bottom) + /** The current height of the notification container. */ val height: Float = bottom - top diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt index 6385d53dbc8b..10b665d8ef01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt @@ -25,7 +25,7 @@ import com.android.internal.logging.MetricsLogger import com.android.internal.logging.nano.MetricsProto import com.android.systemui.common.ui.ConfigurationState import com.android.systemui.common.ui.view.setImportantForAccessibilityYesNo -import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.NotifInflation import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.lifecycle.repeatWhenAttachedToWindow import com.android.systemui.plugins.FalsingManager @@ -76,7 +76,7 @@ import kotlinx.coroutines.flow.stateIn class NotificationListViewBinder @Inject constructor( - @Background private val backgroundDispatcher: CoroutineDispatcher, + @NotifInflation private val inflationDispatcher: CoroutineDispatcher, private val hiderTracker: DisplaySwitchNotificationsHiderTracker, @ShadeDisplayAware private val configuration: ConfigurationState, private val falsingManager: FalsingManager, @@ -155,7 +155,7 @@ constructor( parentView, attachToRoot = false, ) - .flowOn(backgroundDispatcher) + .flowOn(inflationDispatcher) .collectLatest { footerView: FooterView -> traceAsync("bind FooterView") { parentView.setFooterView(footerView) @@ -240,7 +240,7 @@ constructor( parentView, attachToRoot = false, ) - .flowOn(backgroundDispatcher) + .flowOn(inflationDispatcher) .collectLatest { emptyShadeView: EmptyShadeView -> traceAsync("bind EmptyShadeView") { parentView.setEmptyShadeView(emptyShadeView) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt index 54efa4a2bcf2..5c81c8e22bfc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt @@ -44,15 +44,18 @@ import com.android.systemui.keyguard.ui.transitions.PrimaryBouncerTransition import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel +import com.android.systemui.keyguard.ui.viewmodel.AodToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToPrimaryBouncerTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.DozingToDreamingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel @@ -135,7 +138,9 @@ constructor( private val aodToGoneTransitionViewModel: AodToGoneTransitionViewModel, private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel, private val aodToOccludedTransitionViewModel: AodToOccludedTransitionViewModel, + private val aodToGlanceableHubTransitionViewModel: AodToGlanceableHubTransitionViewModel, private val aodToPrimaryBouncerTransitionViewModel: AodToPrimaryBouncerTransitionViewModel, + private val dozingToDreamingTransitionViewModel: DozingToDreamingTransitionViewModel, dozingToGlanceableHubTransitionViewModel: DozingToGlanceableHubTransitionViewModel, private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel, private val dozingToOccludedTransitionViewModel: DozingToOccludedTransitionViewModel, @@ -144,6 +149,7 @@ constructor( private val dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel, private val glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel, + private val glanceableHubToAodTransitionViewModel: GlanceableHubToAodTransitionViewModel, private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel, private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel, private val goneToDreamingTransitionViewModel: GoneToDreamingTransitionViewModel, @@ -571,7 +577,9 @@ constructor( aodToGoneTransitionViewModel.notificationAlpha(viewState), aodToLockscreenTransitionViewModel.notificationAlpha, aodToOccludedTransitionViewModel.lockscreenAlpha(viewState), + aodToGlanceableHubTransitionViewModel.lockscreenAlpha(viewState), aodToPrimaryBouncerTransitionViewModel.notificationAlpha, + dozingToDreamingTransitionViewModel.notificationAlpha, dozingToLockscreenTransitionViewModel.lockscreenAlpha, dozingToOccludedTransitionViewModel.lockscreenAlpha(viewState), dozingToPrimaryBouncerTransitionViewModel.notificationAlpha, @@ -591,6 +599,7 @@ constructor( offToLockscreenTransitionViewModel.lockscreenAlpha, primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha(viewState), glanceableHubToLockscreenTransitionViewModel.keyguardAlpha, + glanceableHubToAodTransitionViewModel.lockscreenAlpha, lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha, ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java index de7215461c80..36193bd87ce2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java @@ -441,6 +441,7 @@ public class KeyguardStatusBarViewController extends ViewController<KeyguardStat mAnimationScheduler.addCallback(mAnimationCallback); mUserInfoController.addCallback(mOnUserInfoChangedListener); mStatusBarStateController.addCallback(mStatusBarStateListener); + mStatusBarState = mStatusBarStateController.getState(); mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); mDisableStateTracker.startTracking(mCommandQueue, mView.getDisplay().getDisplayId()); if (mTintedIconManager == null) { 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 4825a10e901b..15d73d2deb7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -735,6 +735,7 @@ public class NotificationIconContainer extends ViewGroup { private final Consumer<Property> mCannedAnimationEndListener; public IconState(View child) { + super(false /* usePhysicsForMovement */); mView = child; mCannedAnimationEndListener = (property) -> { // If we finished animating out of the shelf diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 6c8e1825ea0a..ba41fd4c40ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -65,6 +65,7 @@ import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeDisplayAware; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor; +import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationClickNotifier; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -116,6 +117,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final static String TAG = "StatusBarNotificationActivityStarter"; private final Context mContext; + private final ShadeDialogContextInteractor mContextInteractor; private final Handler mMainThreadHandler; private final Executor mUiBgExecutor; @@ -156,6 +158,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Inject StatusBarNotificationActivityStarter( @ShadeDisplayAware Context context, + ShadeDialogContextInteractor contextInteractor, @Main Handler mainThreadHandler, @Background Executor uiBgExecutor, NotificationVisibilityProvider visibilityProvider, @@ -188,6 +191,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit PowerInteractor powerInteractor, UserTracker userTracker) { mContext = context; + mContextInteractor = contextInteractor; mMainThreadHandler = mainThreadHandler; mUiBgExecutor = uiBgExecutor; mVisibilityProvider = visibilityProvider; @@ -491,7 +495,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit boolean animate, boolean isActivityIntent) { mLogger.logStartNotificationIntent(entry); - final int displayId = mContext.getDisplayId(); + final int displayId = mContextInteractor.getContext().getDisplayId(); try { ActivityTransitionAnimator.Controller animationController = new StatusBarTransitionAnimatorController( @@ -532,7 +536,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit public void startNotificationGutsIntent(@NonNull final Intent intent, final int appUid, @NonNull ExpandableNotificationRow row) { boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */); - final int displayId = mContext.getDisplayId(); + final int displayId = mContextInteractor.getContext().getDisplayId(); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override public boolean onDismiss() { @@ -571,7 +575,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Override public void startHistoryIntent(View view, boolean showHistory) { ModesEmptyShadeFix.assertInLegacyMode(); - final int displayId = mContext.getDisplayId(); + final int displayId = mContextInteractor.getContext().getDisplayId(); boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override @@ -621,7 +625,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Override public void startSettingsIntent(@NonNull View view, @NonNull SettingsIntent intentInfo) { - final int displayId = mContext.getDisplayId(); + final int displayId = mContextInteractor.getContext().getDisplayId(); boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java index 1dc9de489806..05a46cd9fa31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java @@ -54,6 +54,7 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.kotlin.JavaAdapter; @@ -215,7 +216,11 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, if (ExpandHeadsUpOnInlineReply.isEnabled()) { if (row.isChildInGroup() && !row.areChildrenExpanded()) { // The group isn't expanded, let's make sure it's visible! - mGroupExpansionManager.toggleGroupExpansion(row.getEntry()); + if (NotificationBundleUi.isEnabled()) { + mGroupExpansionManager.toggleGroupExpansion(row.getEntryAdapter()); + } else { + mGroupExpansionManager.toggleGroupExpansion(row.getEntry()); + } } else if (!row.isChildInGroup()) { final boolean expandNotification; if (row.isPinned()) { @@ -233,7 +238,11 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, } else { if (row.isChildInGroup() && !row.areChildrenExpanded()) { // The group isn't expanded, let's make sure it's visible! - mGroupExpansionManager.toggleGroupExpansion(row.getEntry()); + if (NotificationBundleUi.isEnabled()) { + mGroupExpansionManager.toggleGroupExpansion(row.getEntryAdapter()); + } else { + mGroupExpansionManager.toggleGroupExpansion(row.getEntry()); + } } if (android.app.Flags.compactHeadsUpNotificationReply() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java index 144939d1086f..38c0d281b320 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java @@ -443,6 +443,11 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { } public static class StatusIconState extends ViewState { + + public StatusIconState() { + super(false /* usePhysicsForMovement */); + } + /// StatusBarIconView.STATE_* public int visibleState = STATE_ICON; public boolean justAdded = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt index 9f8b45578903..b77e8f2ffefc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt @@ -23,6 +23,10 @@ import com.android.systemui.flags.RefactorFlagUtils @Suppress("NOTHING_TO_INLINE") object StatusBarChipsModernization { /** The aconfig flag name */ + @Deprecated( + "For tests, use @EnableChipsModernization or @DisableChipsModernization " + + "annotations instead" + ) const val FLAG_NAME = Flags.FLAG_STATUS_BAR_CHIPS_MODERNIZATION /** A token used for dependency declaration */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt index 2fd7d82043a0..d6ca656356e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt @@ -150,7 +150,14 @@ constructor( return when { isVisible -> { logger.d({ "Call app is visible: uid=$int1" }) { int1 = model.uid } - OngoingCallModel.InCallWithVisibleApp + OngoingCallModel.InCallWithVisibleApp( + startTimeMs = model.whenTime, + notificationIconView = model.statusBarChipIconView, + intent = model.contentIntent, + notificationKey = model.key, + appName = model.appName, + promotedContent = model.promotedContent, + ) } else -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt index 6507b727eb48..62f0ba032f36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/shared/model/OngoingCallModel.kt @@ -28,8 +28,21 @@ sealed interface OngoingCallModel { /** * There is an ongoing call but the call app is currently visible, so we don't need to show the * chip. + * + * @property startTimeMs see [InCall.startTimeMs]. + * @property notificationIconView see [InCall.notificationIconView]. + * @property intent see [InCall.intent]. + * @property appName see [InCall.appName]. + * @property promotedContent see [InCall.promotedContent]. */ - data object InCallWithVisibleApp : OngoingCallModel + data class InCallWithVisibleApp( + val startTimeMs: Long, + val notificationIconView: StatusBarIconView?, + val intent: PendingIntent?, + val notificationKey: String, + val appName: String, + val promotedContent: PromotedNotificationContentModel?, + ) : OngoingCallModel /** * There *is* an ongoing call. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index a1f7a81e258a..0eabb4ecee84 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -37,10 +37,8 @@ import com.android.systemui.statusbar.pipeline.satellite.ui.model.SatelliteIconM import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest @@ -255,12 +253,7 @@ class MobileIconInteractorImpl( } .stateIn(scope, SharingStarted.WhileSubscribed(), false) - override val isNonTerrestrial: StateFlow<Boolean> = - if (Flags.carrierEnabledSatelliteFlag()) { - connectionRepository.isNonTerrestrial - } else { - MutableStateFlow(false).asStateFlow() - } + override val isNonTerrestrial: StateFlow<Boolean> = connectionRepository.isNonTerrestrial override val isRoaming: StateFlow<Boolean> = combine( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt index 4458b224913b..7eda87f8418d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.view import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import android.widget.FrameLayout import android.widget.ImageView import com.android.systemui.res.R import com.android.systemui.statusbar.StatusBarIconView.getVisibleStateString @@ -61,12 +62,33 @@ class ModernStatusBarMobileView(context: Context, attrs: AttributeSet?) : .also { // Flag-specific configuration if (NewStatusBarIcons.isEnabled) { - val iconView = it.requireViewById<ImageView>(R.id.mobile_signal) - val lp = iconView.layoutParams - lp.height = - context.resources.getDimensionPixelSize( - R.dimen.status_bar_mobile_signal_size_updated - ) + // triangle + it.requireViewById<ImageView>(R.id.mobile_signal).apply { + layoutParams.height = + context.resources.getDimensionPixelSize( + R.dimen.status_bar_mobile_signal_size_updated + ) + } + + // RAT indicator container + it.requireViewById<FrameLayout>(R.id.mobile_type_container).apply { + (layoutParams as MarginLayoutParams).marginEnd = + context.resources.getDimensionPixelSize( + R.dimen.status_bar_mobile_container_margin_end + ) + layoutParams.height = + context.resources.getDimensionPixelSize( + R.dimen.status_bar_mobile_container_height_updated + ) + } + + // RAT indicator + it.requireViewById<ImageView>(R.id.mobile_type).apply { + layoutParams.height = + context.resources.getDimensionPixelSize( + R.dimen.status_bar_mobile_type_size_updated + ) + } } it.subId = viewModel.subscriptionId diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt index 171e4f59b0e5..e37c3f10cfcb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt @@ -23,6 +23,7 @@ import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags.NEW_NETWORK_SLICE_UI import com.android.systemui.log.table.logDiffsForTable import com.android.systemui.res.R +import com.android.systemui.statusbar.core.NewStatusBarIcons import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor @@ -278,10 +279,11 @@ private class CellularIconViewModel( flowOf(null) } else { iconInteractor.showSliceAttribution.map { - if (it) { - Icon.Resource(R.drawable.mobile_network_type_background, null) - } else { - null + when { + it && NewStatusBarIcons.isEnabled -> + Icon.Resource(R.drawable.mobile_network_type_background_updated, null) + it -> Icon.Resource(R.drawable.mobile_network_type_background, null) + else -> null } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt index cd320a12d577..d7348892356d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt @@ -31,6 +31,8 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.statusbar.chips.mediaprojection.domain.model.MediaProjectionStopDialogModel import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips import com.android.systemui.statusbar.chips.ui.binder.OngoingActivityChipBinder +import com.android.systemui.statusbar.chips.ui.binder.OngoingActivityChipViewBinding +import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModelLegacy import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import com.android.systemui.statusbar.core.StatusBarRootModernization @@ -149,6 +151,7 @@ constructor( if (!StatusBarNotifChips.isEnabled && !StatusBarChipsModernization.isEnabled) { val primaryChipViewBinding = OngoingActivityChipBinder.createBinding(primaryChipView) + launch { viewModel.primaryOngoingActivityChip.collect { primaryChipModel -> OngoingActivityChipBinder.bind( @@ -156,18 +159,14 @@ constructor( primaryChipViewBinding, iconViewStore, ) - if (StatusBarRootModernization.isEnabled) { - when (primaryChipModel) { - is OngoingActivityChipModel.Active -> - primaryChipViewBinding.rootView.show( - shouldAnimateChange = true - ) - is OngoingActivityChipModel.Inactive -> - primaryChipViewBinding.rootView.hide( - state = View.GONE, - shouldAnimateChange = primaryChipModel.shouldAnimate, - ) + if (StatusBarRootModernization.isEnabled) { + launch { + bindLegacyPrimaryOngoingActivityChipWithVisibility( + viewModel, + primaryChipModel, + primaryChipViewBinding, + ) } } else { when (primaryChipModel) { @@ -213,12 +212,14 @@ constructor( ) if (StatusBarRootModernization.isEnabled) { - primaryChipViewBinding.rootView.adjustVisibility( - chips.primary.toVisibilityModel() - ) - secondaryChipViewBinding.rootView.adjustVisibility( - chips.secondary.toVisibilityModel() - ) + launch { + bindOngoingActivityChipsWithVisibility( + viewModel, + chips, + primaryChipViewBinding, + secondaryChipViewBinding, + ) + } } else { listener?.onOngoingActivityStatusChanged( hasPrimaryOngoingActivity = @@ -312,6 +313,52 @@ constructor( } } + /** Bind the (legacy) single primary ongoing activity chip with the status bar visibility */ + private suspend fun bindLegacyPrimaryOngoingActivityChipWithVisibility( + viewModel: HomeStatusBarViewModel, + primaryChipModel: OngoingActivityChipModel, + primaryChipViewBinding: OngoingActivityChipViewBinding, + ) { + viewModel.canShowOngoingActivityChips.collectLatest { visible -> + if (!visible) { + primaryChipViewBinding.rootView.hide(shouldAnimateChange = false) + } else { + when (primaryChipModel) { + is OngoingActivityChipModel.Active -> { + primaryChipViewBinding.rootView.show(shouldAnimateChange = true) + } + + is OngoingActivityChipModel.Inactive -> { + primaryChipViewBinding.rootView.hide( + state = View.GONE, + shouldAnimateChange = primaryChipModel.shouldAnimate, + ) + } + } + } + } + } + + /** Bind the primary/secondary chips along with the home status bar's visibility */ + private suspend fun bindOngoingActivityChipsWithVisibility( + viewModel: HomeStatusBarViewModel, + chips: MultipleOngoingActivityChipsModelLegacy, + primaryChipViewBinding: OngoingActivityChipViewBinding, + secondaryChipViewBinding: OngoingActivityChipViewBinding, + ) { + viewModel.canShowOngoingActivityChips.collectLatest { canShow -> + if (!canShow) { + primaryChipViewBinding.rootView.hide(shouldAnimateChange = false) + secondaryChipViewBinding.rootView.hide(shouldAnimateChange = false) + } else { + primaryChipViewBinding.rootView.adjustVisibility(chips.primary.toVisibilityModel()) + secondaryChipViewBinding.rootView.adjustVisibility( + chips.secondary.toVisibilityModel() + ) + } + } + } + private fun SystemEventAnimationState.isAnimatingChip() = when (this) { AnimatingIn, @@ -374,43 +421,42 @@ constructor( if (visibility == View.INVISIBLE || visibility == View.GONE) { return } + alpha = 0f visibility = state } // See CollapsedStatusBarFragment#hide. private fun View.hide(state: Int = View.INVISIBLE, shouldAnimateChange: Boolean) { + animate().cancel() if (visibility == View.INVISIBLE || visibility == View.GONE) { return } - val v = this - v.animate().cancel() if (!shouldAnimateChange) { - v.alpha = 0f - v.visibility = state + alpha = 0f + visibility = state return } - v.animate() + animate() .alpha(0f) .setDuration(CollapsedStatusBarFragment.FADE_OUT_DURATION.toLong()) .setStartDelay(0) .setInterpolator(Interpolators.ALPHA_OUT) - .withEndAction { v.visibility = state } + .withEndAction { visibility = state } } // See CollapsedStatusBarFragment#show. private fun View.show(shouldAnimateChange: Boolean) { - if (visibility == View.VISIBLE) { + animate().cancel() + if (visibility == View.VISIBLE && alpha >= 1f) { return } - val v = this - v.animate().cancel() - v.visibility = View.VISIBLE + visibility = View.VISIBLE if (!shouldAnimateChange) { - v.alpha = 1f + alpha = 1f return } - v.animate() + animate() .alpha(1f) .setDuration(CollapsedStatusBarFragment.FADE_IN_DURATION.toLong()) .setInterpolator(Interpolators.ALPHA_IN) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt index a961713230c8..39a1b46292b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt @@ -255,10 +255,9 @@ fun StatusBarRoot( ) setContent { - val chips = - statusBarViewModel.statusBarPopupChips - .collectAsStateWithLifecycle() - StatusBarPopupChipsContainer(chips = chips.value) + StatusBarPopupChipsContainer( + chips = statusBarViewModel.popupChips + ) } } endSideContent.addView(composeView, 0) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt index d3e37119fdcb..2433d112bc69 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt @@ -27,6 +27,7 @@ import com.android.systemui.common.shared.model.Text import com.android.systemui.common.shared.model.Text.Companion.loadText import com.android.systemui.plugins.qs.QSTile import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon /** Model describing the state that the QS Internet tile should be in. */ sealed interface InternetTileModel { @@ -49,11 +50,14 @@ sealed interface InternetTileModel { state.contentDescription = contentDescription.loadContentDescription(context) // To support both SignalDrawable and other icons, give priority to icons over IDs - if (icon != null) { - state.icon = icon - } else if (iconId != null) { - state.icon = QSTileImpl.maybeLoadResourceIcon(iconId!!, context) - } + state.icon = + when { + icon is ResourceIcon -> + QSTileImpl.maybeLoadResourceIcon((icon as ResourceIcon).resId, context) + icon != null -> icon + iconId != null -> QSTileImpl.maybeLoadResourceIcon(iconId!!, context) + else -> null + } state.state = if (this is Active) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt index f396cbfc8000..807e90567eb7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt @@ -20,6 +20,7 @@ import android.annotation.ColorInt import android.graphics.Rect import android.view.View import androidx.compose.runtime.getValue +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -29,6 +30,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.lifecycle.Activatable import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.Hydrator import com.android.systemui.log.table.TableLogBufferFactory @@ -49,6 +51,7 @@ import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEventAnimationInteractor import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle +import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.StatusBarPopupChipsViewModel import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior @@ -71,6 +74,8 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -94,7 +99,7 @@ import kotlinx.coroutines.flow.stateIn * [StatusBarHideIconsForBouncerManager]. We should move those pieces of logic to this class instead * so that it's all in one place and easily testable outside of the fragment. */ -interface HomeStatusBarViewModel { +interface HomeStatusBarViewModel : Activatable { /** Factory to create the view model for the battery icon */ val batteryViewModelFactory: BatteryViewModel.Factory @@ -133,7 +138,7 @@ interface HomeStatusBarViewModel { val operatorNameViewModel: StatusBarOperatorNameViewModel /** The popup chips that should be shown on the right-hand side of the status bar. */ - val statusBarPopupChips: StateFlow<List<PopupChipModel.Shown>> + val popupChips: List<PopupChipModel.Shown> /** * True if the current scene can show the home status bar (aka this status bar), and false if @@ -144,6 +149,9 @@ interface HomeStatusBarViewModel { */ val isHomeStatusBarAllowedByScene: StateFlow<Boolean> + /** True if the home status bar is showing, and there is no HUN happening */ + val canShowOngoingActivityChips: Flow<Boolean> + /** True if the operator name view is not hidden due to HUN or other visibility state */ val shouldShowOperatorNameView: Flow<Boolean> val isClockVisible: Flow<VisibilityModel> @@ -208,7 +216,7 @@ constructor( shadeInteractor: ShadeInteractor, shareToAppChipViewModel: ShareToAppChipViewModel, ongoingActivityChipsViewModel: OngoingActivityChipsViewModel, - statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel, + statusBarPopupChipsViewModelFactory: StatusBarPopupChipsViewModel.Factory, animations: SystemStatusEventAnimationInteractor, statusBarContentInsetsViewModelStore: StatusBarContentInsetsViewModelStore, @Background bgScope: CoroutineScope, @@ -219,6 +227,8 @@ constructor( val tableLogger = tableLoggerFactory.getOrCreate(tableLogBufferName(thisDisplayId), 200) + private val statusBarPopupChips by lazy { statusBarPopupChipsViewModelFactory.create() } + override val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean> = keyguardTransitionInteractor .isInTransition(Edge.create(from = LOCKSCREEN, to = OCCLUDED)) @@ -246,7 +256,8 @@ constructor( override val ongoingActivityChipsLegacy = ongoingActivityChipsViewModel.chipsLegacy - override val statusBarPopupChips = statusBarPopupChipsViewModel.shownPopupChips + override val popupChips + get() = statusBarPopupChips.shownPopupChips override val isHomeStatusBarAllowedByScene: StateFlow<Boolean> = combine( @@ -404,6 +415,15 @@ constructor( ) .flowOn(bgDispatcher) + override val canShowOngoingActivityChips: Flow<Boolean> = + combine( + isHomeStatusBarAllowed, + keyguardInteractor.isSecureCameraActive, + headsUpNotificationInteractor.statusBarHeadsUpStatus, + ) { isHomeStatusBarAllowed, isSecureCameraActive, headsUpState -> + isHomeStatusBarAllowed && !isSecureCameraActive && !headsUpState.isPinned + } + override val isClockVisible: Flow<VisibilityModel> = combine( shouldHomeStatusBarBeVisible, @@ -495,7 +515,13 @@ constructor( private fun Boolean.toVisibleOrInvisible(): Int = if (this) View.VISIBLE else View.INVISIBLE override suspend fun onActivated(): Nothing { - hydrator.activate() + coroutineScope { + launch { hydrator.activate() } + if (StatusBarPopupChips.isEnabled) { + launch { statusBarPopupChips.activate() } + } + awaitCancellation() + } } /** Inject this to create the display-dependent view model */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java index 88cf46a0ca07..b13e01be40f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceStateRotationLockSettingController.java @@ -29,7 +29,6 @@ import androidx.annotation.NonNull; import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.systemui.Dumpable; -import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.util.wrapper.RotationPolicyWrapper; @@ -43,7 +42,6 @@ import javax.inject.Inject; * Handles reading and writing of rotation lock settings per device state, as well as setting the * rotation lock when device state changes. */ -@SysUISingleton public final class DeviceStateRotationLockSettingController implements Listenable, RotationLockController.RotationLockControllerCallback, Dumpable { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java index 797aa1f3a3dd..3ee7f33e3d3a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java @@ -27,8 +27,10 @@ import androidx.annotation.NonNull; import com.android.internal.view.RotationPolicy.RotationPolicyListener; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.rotationlock.DeviceStateAutoRotateModule.BoundsDeviceStateAutoRotateModule; import com.android.systemui.util.wrapper.RotationPolicyWrapper; +import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; import javax.inject.Inject; @@ -50,21 +52,25 @@ public final class RotationLockControllerImpl implements RotationLockController }; private final RotationPolicyWrapper mRotationPolicy; - private final DeviceStateRotationLockSettingController + private final Optional<DeviceStateRotationLockSettingController> mDeviceStateRotationLockSettingController; private final boolean mIsPerDeviceStateRotationLockEnabled; @Inject public RotationLockControllerImpl( RotationPolicyWrapper rotationPolicyWrapper, - DeviceStateRotationLockSettingController deviceStateRotationLockSettingController, + Optional<DeviceStateRotationLockSettingController> + deviceStateRotationLockSettingController, @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults ) { mRotationPolicy = rotationPolicyWrapper; - mDeviceStateRotationLockSettingController = deviceStateRotationLockSettingController; mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0; - if (mIsPerDeviceStateRotationLockEnabled) { - mCallbacks.add(mDeviceStateRotationLockSettingController); + mDeviceStateRotationLockSettingController = + deviceStateRotationLockSettingController; + + if (mIsPerDeviceStateRotationLockEnabled + && mDeviceStateRotationLockSettingController.isPresent()) { + mCallbacks.add(mDeviceStateRotationLockSettingController.get()); } setListening(true); @@ -113,8 +119,9 @@ public final class RotationLockControllerImpl implements RotationLockController } else { mRotationPolicy.unregisterRotationPolicyListener(mRotationPolicyListener); } - if (mIsPerDeviceStateRotationLockEnabled) { - mDeviceStateRotationLockSettingController.setListening(listening); + if (mIsPerDeviceStateRotationLockEnabled + && mDeviceStateRotationLockSettingController.isPresent()) { + mDeviceStateRotationLockSettingController.get().setListening(listening); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java index 9ab8175e13b8..36513f77f1a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java @@ -24,6 +24,9 @@ import static com.android.systemui.Flags.screenshareNotificationHidingBugFix; import android.annotation.MainThread; import android.app.IActivityManager; +import android.app.role.OnRoleHoldersChangedListener; +import android.app.role.RoleManager; +import android.companion.AssociationRequest; import android.content.Context; import android.content.pm.PackageManager; import android.database.ExecutorContentObserver; @@ -51,6 +54,8 @@ import com.android.systemui.util.Assert; import com.android.systemui.util.ListenerSet; import com.android.systemui.util.settings.GlobalSettings; +import java.util.List; +import java.util.Objects; import java.util.Random; import java.util.concurrent.Executor; @@ -63,12 +68,14 @@ public class SensitiveNotificationProtectionControllerImpl private static final String LOG_TAG = "SNPC"; private final SensitiveNotificationProtectionControllerLogger mLogger; private final PackageManager mPackageManager; + private final RoleManager mRoleManager; // Packages exempt from projection session protections (if they start a projection session) private final ArraySet<String> mSessionProtectionExemptPackages = new ArraySet<>(); // Packages exempt from individual notification protections (if they post a notification) private final ArraySet<String> mNotificationProtectionExemptPackages = new ArraySet<>(); private final ListenerSet<Runnable> mListeners = new ListenerSet<>(); private volatile MediaProjectionInfo mProjection; + private ArraySet<RoleHolder> mNotificationProtectionExemptByRolePackages = new ArraySet<>(); private SensitiveNotificatioMediaProjectionSession mActiveMediaProjectionSession; boolean mDisableScreenShareProtections = false; @@ -128,6 +135,27 @@ public class SensitiveNotificationProtectionControllerImpl } }; + @VisibleForTesting + final OnRoleHoldersChangedListener mRoleHoldersChangedListener = + new OnRoleHoldersChangedListener() { + @Override + public void onRoleHoldersChanged(@NonNull String roleName, + @NonNull UserHandle user) { + if (!roleName.equals(AssociationRequest.DEVICE_PROFILE_APP_STREAMING)) { + return; + } + + List<String> appStreamingRoleHolders = mRoleManager.getRoleHoldersAsUser( + roleName, user); + ArraySet<RoleHolder> roleHolders = new ArraySet<>(); + for (String appStreamingRoleHolder : appStreamingRoleHolders) { + RoleHolder roleHolder = new RoleHolder(appStreamingRoleHolder, user); + roleHolders.add(roleHolder); + } + mNotificationProtectionExemptByRolePackages = roleHolders; + } + }; + private void logSensitiveContentProtectionSessionStart( long sessionId, int projectionAppUid, boolean exempt) { mActiveMediaProjectionSession = @@ -166,11 +194,13 @@ public class SensitiveNotificationProtectionControllerImpl IActivityManager activityManager, PackageManager packageManager, TelephonyManager telephonyManager, + RoleManager roleManager, @Main Handler mainHandler, @Background Executor bgExecutor, SensitiveNotificationProtectionControllerLogger logger) { mLogger = logger; mPackageManager = packageManager; + mRoleManager = roleManager; if (!screenshareNotificationHiding()) { return; @@ -215,6 +245,8 @@ public class SensitiveNotificationProtectionControllerImpl }); mediaProjectionManager.addCallback(mMediaProjectionCallback, mainHandler); + roleManager.addOnRoleHoldersChangedListenerAsUser(bgExecutor, mRoleHoldersChangedListener, + UserHandle.ALL); } @NonNull @@ -314,6 +346,10 @@ public class SensitiveNotificationProtectionControllerImpl Log.w(LOG_TAG, "Screen share protections exempt for package " + info.getPackageName() + " via permission"); return null; + } else if (info != null && isAppStreamingRoleHolder(info)) { + Log.w(LOG_TAG, "Screen share protections exempt for package " + info.getPackageName() + + " via role(s) held"); + return null; } else if (info != null && info.getLaunchCookie() != null) { // Only enable sensitive content protection if sharing full screen // Launch cookie only set (non-null) if sharing single app/task @@ -323,11 +359,16 @@ public class SensitiveNotificationProtectionControllerImpl return info; } + private boolean isAppStreamingRoleHolder(@NonNull MediaProjectionInfo info) { + return mNotificationProtectionExemptByRolePackages.contains( + new RoleHolder(info.getPackageName(), info.getUserHandle())); + } + private boolean canRecordSensitiveContent(@NonNull String packageName) { // RECORD_SENSITIVE_CONTENT is flagged api on sensitiveNotificationAppProtection if (sensitiveNotificationAppProtection()) { return mPackageManager.checkPermission( - android.Manifest.permission.RECORD_SENSITIVE_CONTENT, packageName) + android.Manifest.permission.RECORD_SENSITIVE_CONTENT, packageName) == PackageManager.PERMISSION_GRANTED; } return false; @@ -382,4 +423,26 @@ public class SensitiveNotificationProtectionControllerImpl boolean userForcesRedaction = entry.isChannelVisibilityPrivate(); return notificationRequestsRedaction || userForcesRedaction; } + + private static final class RoleHolder { + private final String mPackageName; + private final UserHandle mUserHandle; + + RoleHolder(String packageName, UserHandle userHandle) { + mPackageName = packageName; + mUserHandle = userHandle; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof RoleHolder that)) return false; + return Objects.equals(mPackageName, that.mPackageName) && Objects.equals( + mUserHandle, that.mUserHandle); + } + + @Override + public int hashCode() { + return Objects.hash(mPackageName, mUserHandle); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt index 33ed419afef2..5dbe9b145bc7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/ModesDialogEventLogger.kt @@ -21,29 +21,25 @@ import com.android.settingslib.notification.modes.ZenMode import com.android.systemui.qs.QSModesEvent import javax.inject.Inject -class ModesDialogEventLogger -@Inject -constructor( - private val uiEventLogger: UiEventLogger, -) { +class ModesDialogEventLogger @Inject constructor(private val uiEventLogger: UiEventLogger) { fun logModeOn(mode: ZenMode) { val id = if (mode.isManualDnd) QSModesEvent.QS_MODES_DND_ON else QSModesEvent.QS_MODES_MODE_ON - uiEventLogger.log(id, /* uid= */ 0, mode.rule.packageName) + uiEventLogger.log(id, /* uid= */ 0, mode.ownerPackage) } fun logModeOff(mode: ZenMode) { val id = if (mode.isManualDnd) QSModesEvent.QS_MODES_DND_OFF else QSModesEvent.QS_MODES_MODE_OFF - uiEventLogger.log(id, /* uid= */ 0, mode.rule.packageName) + uiEventLogger.log(id, /* uid= */ 0, mode.ownerPackage) } fun logModeSettings(mode: ZenMode) { val id = if (mode.isManualDnd) QSModesEvent.QS_MODES_DND_SETTINGS else QSModesEvent.QS_MODES_MODE_SETTINGS - uiEventLogger.log(id, /* uid= */ 0, mode.rule.packageName) + uiEventLogger.log(id, /* uid= */ 0, mode.ownerPackage) } fun logOpenDurationDialog(mode: ZenMode) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt index 07f1c3470c83..dc07202dc486 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModel.kt @@ -71,10 +71,10 @@ constructor( mode.id in prevIds -> true // Mode is enabled -> show if active (so user can toggle off), or if it // can be manually toggled on - mode.rule.isEnabled -> mode.isActive || mode.rule.isManualInvocationAllowed + mode.isEnabled -> mode.isActive || mode.isManualInvocationAllowed // Mode was created as disabled, or disabled by the app that owns it -> // will be shown with a "Not set" text - !mode.rule.isEnabled -> mode.status == ZenMode.Status.DISABLED_BY_OTHER + !mode.isEnabled -> mode.status == ZenMode.Status.DISABLED_BY_OTHER else -> false } } @@ -97,13 +97,13 @@ constructor( if (mode.isActive) R.string.zen_mode_on else R.string.zen_mode_off ), onClick = { - if (!mode.rule.isEnabled) { + if (!mode.isEnabled) { openSettings(mode) } else if (mode.isActive) { dialogEventLogger.logModeOff(mode) zenModeInteractor.deactivateMode(mode) } else { - if (mode.rule.isManualInvocationAllowed) { + if (mode.isManualInvocationAllowed) { if (zenModeInteractor.shouldAskForZenDuration(mode)) { dialogEventLogger.logOpenDurationDialog(mode) // NOTE: The dialog handles turning on the mode itself. @@ -144,10 +144,10 @@ constructor( * readers, and for the tile subtext will be augmented with the current status of the mode. */ private fun getModeDescription(mode: ZenMode, forAccessibility: Boolean): String? { - if (!mode.rule.isEnabled) { + if (!mode.isEnabled) { return context.resources.getString(R.string.zen_mode_set_up) } - if (!mode.rule.isManualInvocationAllowed && !mode.isActive) { + if (!mode.isManualInvocationAllowed && !mode.isActive) { return context.resources.getString(R.string.zen_mode_no_manual_invocation) } return if (forAccessibility) diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index 28cf78f6777e..9f60fe212567 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -18,8 +18,10 @@ package com.android.systemui.theme; import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8; +import static com.android.systemui.Flags.hardwareColorStyles; import static com.android.systemui.Flags.themeOverlayControllerWakefulnessDeprecation; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; +import static com.android.systemui.monet.ColorScheme.GOOGLE_BLUE; import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_HOME; import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_LOCK; import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET; @@ -73,6 +75,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.flags.SystemPropertiesHelper; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.keyguard.shared.model.KeyguardState; @@ -99,6 +102,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -136,9 +140,11 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { private final DeviceProvisionedController mDeviceProvisionedController; private final Resources mResources; // Current wallpaper colors associated to a user. - private final SparseArray<WallpaperColors> mCurrentColors = new SparseArray<>(); + @VisibleForTesting + protected final SparseArray<WallpaperColors> mCurrentColors = new SparseArray<>(); private final WallpaperManager mWallpaperManager; private final ActivityManager mActivityManager; + protected final SystemPropertiesHelper mSystemPropertiesHelper; @VisibleForTesting protected ColorScheme mColorScheme; // If fabricated overlays were already created for the current theme. @@ -423,7 +429,9 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { JavaAdapter javaAdapter, KeyguardTransitionInteractor keyguardTransitionInteractor, UiModeManager uiModeManager, - ActivityManager activityManager) { + ActivityManager activityManager, + SystemPropertiesHelper systemPropertiesHelper + ) { mContext = context; mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET); mIsFidelityEnabled = featureFlags.isEnabled(Flags.COLOR_FIDELITY); @@ -443,6 +451,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { mKeyguardTransitionInteractor = keyguardTransitionInteractor; mUiModeManager = uiModeManager; mActivityManager = activityManager; + mSystemPropertiesHelper = systemPropertiesHelper; dumpManager.registerDumpable(TAG, this); Flow<Boolean> isFinishedInAsleepStateFlow = mKeyguardTransitionInteractor @@ -498,29 +507,38 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { mUserTracker.addCallback(mUserTrackerCallback, mMainExecutor); mDeviceProvisionedController.addCallback(mDeviceProvisionedListener); + WallpaperColors systemColor; + if (hardwareColorStyles() && !mDeviceProvisionedController.isCurrentUserSetup()) { + Pair<Integer, Color> defaultSettings = getThemeSettingsDefaults(); + mThemeStyle = defaultSettings.first; + Color seedColor = defaultSettings.second; + + // we only use the first color anyway, so we can pass only the single color we have + systemColor = new WallpaperColors( + /*primaryColor*/ seedColor, + /*secondaryColor*/ seedColor, + /*tertiaryColor*/ seedColor + ); + } else { + systemColor = mWallpaperManager.getWallpaperColors( + getDefaultWallpaperColorsSource(mUserTracker.getUserId())); + } + // Upon boot, make sure we have the most up to date colors Runnable updateColors = () -> { - WallpaperColors systemColor = mWallpaperManager.getWallpaperColors( - getDefaultWallpaperColorsSource(mUserTracker.getUserId())); - Runnable applyColors = () -> { - if (DEBUG) Log.d(TAG, "Boot colors: " + systemColor); - mCurrentColors.put(mUserTracker.getUserId(), systemColor); - reevaluateSystemTheme(false /* forceReload */); - }; - if (mDeviceProvisionedController.isCurrentUserSetup()) { - mMainExecutor.execute(applyColors); - } else { - applyColors.run(); - } + if (DEBUG) Log.d(TAG, "Boot colors: " + systemColor); + mCurrentColors.put(mUserTracker.getUserId(), systemColor); + reevaluateSystemTheme(false /* forceReload */); }; // Whenever we're going directly to setup wizard, we need to process colors synchronously, // otherwise we'll see some jank when the activity is recreated. if (!mDeviceProvisionedController.isCurrentUserSetup()) { - updateColors.run(); + mMainExecutor.execute(updateColors); } else { mBgExecutor.execute(updateColors); } + mWallpaperManager.addOnColorsChangedListener(mOnColorsChangedListener, null, UserHandle.USER_ALL); @@ -604,7 +622,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { @VisibleForTesting protected boolean isPrivateProfile(UserHandle userHandle) { - Context usercontext = mContext.createContextAsUser(userHandle,0); + Context usercontext = mContext.createContextAsUser(userHandle, 0); return usercontext.getSystemService(UserManager.class).isPrivateProfile(); } @@ -720,6 +738,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { return true; } + @SuppressWarnings("StringCaseLocaleUsage") // Package name is not localized private void updateThemeOverlays() { final int currentUser = mUserTracker.getUserId(); final String overlayPackageJson = mSecureSettings.getStringForUser( @@ -746,7 +765,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { OverlayIdentifier systemPalette = categoryToPackage.get(OVERLAY_CATEGORY_SYSTEM_PALETTE); if (mIsMonetEnabled && systemPalette != null && systemPalette.getPackageName() != null) { try { - String colorString = systemPalette.getPackageName().toLowerCase(); + String colorString = systemPalette.getPackageName().toLowerCase(); if (!colorString.startsWith("#")) { colorString = "#" + colorString; } @@ -856,6 +875,75 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { return style; } + protected Pair<Integer, String> getHardwareColorSetting() { + String deviceColorProperty = "ro.boot.hardware.color"; + + String[] themeData = mResources.getStringArray( + com.android.internal.R.array.theming_defaults); + + // Color can be hex (`#FF0000`) or `home_wallpaper` + Map<String, Pair<Integer, String>> themeMap = new HashMap<>(); + + // extract all theme settings + for (String themeEntry : themeData) { + String[] themeComponents = themeEntry.split("\\|"); + if (themeComponents.length != 3) continue; + themeMap.put(themeComponents[0], + new Pair<>(Style.valueOf(themeComponents[1]), themeComponents[2])); + } + + Pair<Integer, String> fallbackTheme = themeMap.get("*"); + if (fallbackTheme == null) { + Log.d(TAG, "Theming wildcard not found. Fallback to TONAL_SPOT|" + COLOR_SOURCE_HOME); + fallbackTheme = new Pair<>(Style.TONAL_SPOT, COLOR_SOURCE_HOME); + } + + String deviceColorPropertyValue = mSystemPropertiesHelper.get(deviceColorProperty); + Pair<Integer, String> selectedTheme = themeMap.get(deviceColorPropertyValue); + if (selectedTheme == null) { + Log.d(TAG, "Sysprop `" + deviceColorProperty + "` of value '" + deviceColorPropertyValue + + "' not found in theming_defaults: " + Arrays.toString(themeData)); + selectedTheme = fallbackTheme; + } + + return selectedTheme; + } + + @VisibleForTesting + protected Pair<Integer, Color> getThemeSettingsDefaults() { + + Pair<Integer, String> selectedTheme = getHardwareColorSetting(); + + // Last fallback color + Color defaultSeedColor = Color.valueOf(GOOGLE_BLUE); + + // defaultColor will come from wallpaper or be parsed from a string + boolean isWallpaper = selectedTheme.second.equals(COLOR_SOURCE_HOME); + + if (isWallpaper) { + WallpaperColors wallpaperColors = mWallpaperManager.getWallpaperColors( + getDefaultWallpaperColorsSource(mUserTracker.getUserId())); + + if (wallpaperColors != null) { + defaultSeedColor = wallpaperColors.getPrimaryColor(); + } + + Log.d(TAG, "Default seed color read from home wallpaper: " + Integer.toHexString( + defaultSeedColor.toArgb())); + } else { + try { + defaultSeedColor = Color.valueOf(Color.parseColor(selectedTheme.second)); + Log.d(TAG, "Default seed color read from resource: " + Integer.toHexString( + defaultSeedColor.toArgb())); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Error parsing color: " + selectedTheme.second, e); + // defaultSeedColor remains unchanged in this case + } + } + + return new Pair<>(selectedTheme.first, defaultSeedColor); + } + @Override public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { pw.println("mSystemColors=" + mCurrentColors); diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt index a2125c8f0955..d8a9527b22ab 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt @@ -130,22 +130,32 @@ private class ScreensProvider( val easterEggGestureViewModel: EasterEggGestureViewModel, ) : TouchpadTutorialScreensProvider { @Composable - override fun BackGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { + override fun BackGesture( + onDoneButtonClicked: () -> Unit, + onBack: () -> Unit, + isAutoProceed: Boolean, + ) { BackGestureTutorialScreen( backGestureScreenViewModel, easterEggGestureViewModel, onDoneButtonClicked, onBack, + isAutoProceed, ) } @Composable - override fun HomeGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) { + override fun HomeGesture( + onDoneButtonClicked: () -> Unit, + onBack: () -> Unit, + isAutoProceed: Boolean, + ) { HomeGestureTutorialScreen( homeGestureScreenViewModel, easterEggGestureViewModel, onDoneButtonClicked, onBack, + isAutoProceed, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt index bce55cbdcc4a..c28483c55952 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt @@ -33,6 +33,7 @@ fun BackGestureTutorialScreen( easterEggGestureViewModel: EasterEggGestureViewModel, onDoneButtonClicked: () -> Unit, onBack: () -> Unit, + isAutoProceed: Boolean = false, ) { val screenConfig = TutorialScreenConfig( @@ -47,6 +48,7 @@ fun BackGestureTutorialScreen( bodyErrorResId = R.string.touchpad_back_gesture_error_body, ), animations = TutorialScreenConfig.Animations(educationResId = R.raw.trackpad_back_edu), + hasNextButton = isAutoProceed, ) GestureTutorialScreen( screenConfig = screenConfig, diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt index 4acdb6070200..b238a8db31f8 100644 --- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt +++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt @@ -32,6 +32,7 @@ fun HomeGestureTutorialScreen( easterEggGestureViewModel: EasterEggGestureViewModel, onDoneButtonClicked: () -> Unit, onBack: () -> Unit, + isAutoProceed: Boolean = false, ) { val screenConfig = TutorialScreenConfig( @@ -46,6 +47,7 @@ fun HomeGestureTutorialScreen( bodyErrorResId = R.string.touchpad_home_gesture_error_body, ), animations = TutorialScreenConfig.Animations(educationResId = R.raw.trackpad_home_edu), + hasNextButton = isAutoProceed, ) GestureTutorialScreen( screenConfig = screenConfig, diff --git a/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyLogger.kt b/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyLogger.kt index 76f7609f81c7..47e27bc59f96 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyLogger.kt @@ -49,6 +49,7 @@ class DisplaySwitchLatencyLogger { hallSensorToDeviceStateChangeMs, onScreenTurningOnToOnDrawnMs, onDrawnToOnScreenTurnedOnMs, + trackingResult, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyTracker.kt index e1640cd4ce7a..66de52260b79 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/DisplaySwitchLatencyTracker.kt @@ -37,12 +37,16 @@ import com.android.systemui.power.shared.model.WakefulnessModel import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.shared.system.SysUiStatsLog import com.android.systemui.unfold.DisplaySwitchLatencyTracker.DisplaySwitchLatencyEvent +import com.android.systemui.unfold.DisplaySwitchLatencyTracker.TrackingResult.CORRUPTED +import com.android.systemui.unfold.DisplaySwitchLatencyTracker.TrackingResult.SUCCESS +import com.android.systemui.unfold.DisplaySwitchLatencyTracker.TrackingResult.TIMED_OUT import com.android.systemui.unfold.dagger.UnfoldSingleThreadBg import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionStarted import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor import com.android.systemui.util.Compile import com.android.systemui.util.Utils.isDeviceFoldable import com.android.systemui.util.animation.data.repository.AnimationStatusRepository +import com.android.systemui.util.kotlin.WithPrev import com.android.systemui.util.kotlin.pairwise import com.android.systemui.util.kotlin.race import com.android.systemui.util.time.SystemClock @@ -56,7 +60,6 @@ import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.filter @@ -116,10 +119,9 @@ constructor( latencyTracker.onActionStart(ACTION_SWITCH_DISPLAY_UNFOLD) instantForTrack(TAG) { "unfold latency tracking started" } } + val event = DisplaySwitchLatencyEvent().withBeforeFields(previousState.toStatsInt()) try { withTimeout(SCREEN_EVENT_TIMEOUT) { - val event = - DisplaySwitchLatencyEvent().withBeforeFields(previousState.toStatsInt()) val displaySwitchTimeMs = measureTimeMillis(systemClock) { traceAsync(TAG, "displaySwitch") { @@ -134,27 +136,43 @@ constructor( } catch (e: TimeoutCancellationException) { instantForTrack(TAG) { "tracking timed out" } latencyTracker.onActionCancel(ACTION_SWITCH_DISPLAY_UNFOLD) + logDisplaySwitchEvent( + event = event, + toFoldableDeviceState = newState, + displaySwitchTimeMs = SCREEN_EVENT_TIMEOUT.inWholeMilliseconds, + trackingResult = TIMED_OUT, + ) } catch (e: CancellationException) { instantForTrack(TAG) { "new state interrupted, entering cool down" } latencyTracker.onActionCancel(ACTION_SWITCH_DISPLAY_UNFOLD) - startCoolDown() + startCoolDown(event) } } } } @OptIn(FlowPreview::class) - private fun startCoolDown() { + private fun startCoolDown(event: DisplaySwitchLatencyEvent) { if (isCoolingDown) return isCoolingDown = true applicationScope.launch(context = backgroundDispatcher) { val startTime = systemClock.elapsedRealtime() + var lastState: DeviceState? = null try { - startOrEndEvent.timeout(COOL_DOWN_DURATION).collect() - } catch (e: TimeoutCancellationException) { - instantForTrack(TAG) { - "cool down finished, lasted ${systemClock.elapsedRealtime() - startTime} ms" + startOrEndEvent.timeout(COOL_DOWN_DURATION).collect { + if (it is WithPrev<*, *>) { + lastState = it.newValue as? DeviceState + } } + } catch (e: TimeoutCancellationException) { + val totalCooldownTime = systemClock.elapsedRealtime() - startTime + logDisplaySwitchEvent( + event = event, + toFoldableDeviceState = lastState ?: DeviceState.UNKNOWN, + displaySwitchTimeMs = totalCooldownTime, + trackingResult = CORRUPTED, + ) + instantForTrack(TAG) { "cool down finished, lasted $totalCooldownTime ms" } isCoolingDown = false } } @@ -164,12 +182,14 @@ constructor( event: DisplaySwitchLatencyEvent, toFoldableDeviceState: DeviceState, displaySwitchTimeMs: Long, + trackingResult: TrackingResult = SUCCESS, ) { displaySwitchLatencyLogger.log( event.withAfterFields( - toFoldableDeviceState.toStatsInt(), - displaySwitchTimeMs.toInt(), + toFoldableDeviceState, + displaySwitchTimeMs, getCurrentState(), + trackingResult, ) ) } @@ -183,6 +203,13 @@ constructor( else -> FOLDABLE_DEVICE_STATE_UNKNOWN } + private fun TrackingResult.toStatsInt(): Int = + when (this) { + SUCCESS -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TRACKING_RESULT__SUCCESS + CORRUPTED -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TRACKING_RESULT__CORRUPTED + TIMED_OUT -> SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TRACKING_RESULT__TIMED_OUT + } + private suspend fun waitForDisplaySwitch(toFoldableDeviceState: Int) { val isTransitionEnabled = unfoldTransitionInteractor.isAvailable && @@ -264,21 +291,24 @@ constructor( } private fun DisplaySwitchLatencyEvent.withAfterFields( - toFoldableDeviceState: Int, - displaySwitchTimeMs: Int, + toFoldableDeviceState: DeviceState, + displaySwitchTimeMs: Long, toState: Int, + trackingResult: TrackingResult, ): DisplaySwitchLatencyEvent { log { - "toFoldableDeviceState=$toFoldableDeviceState, " + + "trackingResult=$trackingResult, " + + "toFoldableDeviceState=$toFoldableDeviceState, " + "toState=$toState, " + "latencyMs=$displaySwitchTimeMs" } instantForTrack(TAG) { "toFoldableDeviceState=$toFoldableDeviceState, toState=$toState" } return copy( - toFoldableDeviceState = toFoldableDeviceState, - latencyMs = displaySwitchTimeMs, + toFoldableDeviceState = toFoldableDeviceState.toStatsInt(), + latencyMs = displaySwitchTimeMs.toInt(), toState = toState, + trackingResult = trackingResult.toStatsInt(), ) } @@ -312,8 +342,16 @@ constructor( val hallSensorToDeviceStateChangeMs: Int = VALUE_UNKNOWN, val onScreenTurningOnToOnDrawnMs: Int = VALUE_UNKNOWN, val onDrawnToOnScreenTurnedOnMs: Int = VALUE_UNKNOWN, + val trackingResult: Int = + SysUiStatsLog.DISPLAY_SWITCH_LATENCY_TRACKED__TRACKING_RESULT__UNKNOWN_RESULT, ) + enum class TrackingResult { + SUCCESS, + CORRUPTED, + TIMED_OUT, + } + companion object { private const val VALUE_UNKNOWN = -1 private const val TAG = "DisplaySwitchLatency" diff --git a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java index 32f2ca6fb696..367f54cf4936 100644 --- a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java +++ b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java @@ -147,7 +147,7 @@ public class CreateUserActivity extends Activity { super.onDestroy(); } - private void addUserNow(String userName, Drawable userIcon, Boolean isAdmin) { + private void addUserNow(String userName, Drawable userIcon, String iconPath, Boolean isAdmin) { mSetupUserDialog.dismiss(); userName = (userName == null || userName.trim().isEmpty()) ? getString(com.android.settingslib.R.string.user_new_user_name) diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt index e5c1e7daa25a..79ff38eabc08 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt @@ -21,6 +21,7 @@ import com.android.systemui.coroutines.newTracingContext import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.NotifInflation import com.android.systemui.dagger.qualifiers.UiBackground import com.android.systemui.util.settings.SettingsSingleThreadBackground import dagger.Module @@ -123,4 +124,19 @@ class SysUICoroutinesModule { ): CoroutineContext { return uiBgCoroutineDispatcher } + + /** Coroutine dispatcher for background notification inflation. */ + @Provides + @NotifInflation + @SysUISingleton + fun notifInflationCoroutineDispatcher( + @NotifInflation notifInflationExecutor: Executor, + @Background bgCoroutineDispatcher: CoroutineDispatcher, + ): CoroutineDispatcher { + if (com.android.systemui.Flags.useNotifInflationThreadForFooter()) { + return notifInflationExecutor.asCoroutineDispatcher() + } else { + return bgCoroutineDispatcher + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index ae3756d390af..6fc95610159a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -308,9 +308,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private int mWindowGravity; @VisibleForTesting - final int mVolumeRingerIconDrawableId = R.drawable.ic_speaker_on; + final int mVolumeRingerIconDrawableId = R.drawable.ic_legacy_speaker_on; @VisibleForTesting - final int mVolumeRingerMuteIconDrawableId = R.drawable.ic_speaker_mute; + final int mVolumeRingerMuteIconDrawableId = R.drawable.ic_legacy_speaker_mute; private int mOriginalGravity; private final DevicePostureController.Callback mDevicePostureControllerCallback; @@ -1791,8 +1791,9 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, enableRingerViewsH(!isZenMuted); switch (mState.ringerModeInternal) { case AudioManager.RINGER_MODE_VIBRATE: - mRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate); - mSelectedRingerIcon.setImageResource(R.drawable.ic_volume_ringer_vibrate); + mRingerIcon.setImageResource(R.drawable.ic_legacy_volume_ringer_vibrate); + mSelectedRingerIcon.setImageResource( + R.drawable.ic_legacy_volume_ringer_vibrate); addAccessibilityDescription(mRingerIcon, RINGER_MODE_VIBRATE, mContext.getString(R.string.volume_ringer_hint_mute)); mRingerIcon.setTag(Events.ICON_STATE_VIBRATE); @@ -1990,7 +1991,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, if (zenMuted) { iconRes = com.android.internal.R.drawable.ic_qs_dnd; } else if (isRingVibrate) { - iconRes = R.drawable.ic_volume_ringer_vibrate; + iconRes = R.drawable.ic_legacy_volume_ringer_vibrate; } else if (isRingSilent) { iconRes = row.iconMuteRes; } else if (ss.routedToBluetooth) { @@ -2009,7 +2010,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, row.setIcon(iconRes, mContext.getTheme()); row.iconState = - iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE + iconRes == R.drawable.ic_legacy_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes) ? Events.ICON_STATE_MUTE : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt index ef750574830a..0bdf99e49b1b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt @@ -27,6 +27,8 @@ import androidx.constraintlayout.motion.widget.MotionLayout import androidx.dynamicanimation.animation.FloatValueHolder import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce +import com.android.app.tracing.coroutines.launchInTraced +import com.android.app.tracing.coroutines.launchTraced import com.android.internal.R as internalR import com.android.systemui.res.R import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope @@ -47,9 +49,7 @@ import kotlin.properties.Delegates import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest -import kotlinx.coroutines.launch private const val CLOSE_DRAWER_DELAY = 300L // Ensure roundness and color of button is updated when progress is changed by a minimum fraction. @@ -107,13 +107,6 @@ constructor( fullRadius = volumeDialogBgFullRadius, diff = volumeDialogBgFullRadius - volumeDialogBgSmallRadius, progress, - isBottom = false, - ) - volumeDialogBackgroundView.applyCorners( - fullRadius = volumeDialogBgFullRadius, - diff = volumeDialogBgFullRadius - volumeDialogBgSmallRadius, - progress, - isBottom = true, ) } val ringerDrawerTransitionListener = VolumeDialogRingerDrawerTransitionListener { @@ -122,7 +115,9 @@ constructor( drawerContainer.setTransitionListener(ringerDrawerTransitionListener) volumeDialogBackgroundView.background = volumeDialogBackgroundView.background.mutate() ringerBackgroundView.background = ringerBackgroundView.background.mutate() - launch { dialogViewModel.addTouchableBounds(ringerBackgroundView) } + launchTraced("VDRVB#addTouchableBounds") { + dialogViewModel.addTouchableBounds(ringerBackgroundView) + } viewModel.ringerViewModel .mapLatest { ringerState -> @@ -132,10 +127,10 @@ constructor( // Set up view background and visibility drawerContainer.visibility = View.VISIBLE + (volumeDialogBackgroundView.background as GradientDrawable).cornerRadii = + bottomCornerRadii when (uiModel.drawerState) { is RingerDrawerState.Initial -> { - (volumeDialogBackgroundView.background as GradientDrawable) - .cornerRadii = bottomCornerRadii drawerContainer.animateAndBindDrawerButtons( viewModel, uiModel, @@ -216,8 +211,6 @@ constructor( drawerContainer.transitionToState( R.id.volume_dialog_ringer_drawer_open ) - volumeDialogBackgroundView.background = - volumeDialogBackgroundView.background.mutate() ringerBackgroundView.background = ringerBackgroundView.background.mutate() } @@ -231,7 +224,7 @@ constructor( } } } - .launchIn(this) + .launchInTraced("VDRVB#ringerViewModel", this) } private suspend fun MotionLayout.animateAndBindDrawerButtons( @@ -261,7 +254,7 @@ constructor( val selectedCornerRadius = (selectedButton.background as GradientDrawable).cornerRadius if (selectedCornerRadius.toInt() != selectedButtonUiModel.cornerRadius) { - launch { + launchTraced("VDRVB#selectedButtonAnimation") { selectedButton.animateTo( selectedButtonUiModel, if (uiModel.currentButtonIndex == count - 1) { @@ -275,7 +268,7 @@ constructor( val unselectedCornerRadius = (unselectedButton.background as GradientDrawable).cornerRadius if (unselectedCornerRadius.toInt() != unselectedButtonUiModel.cornerRadius) { - launch { + launchTraced("VDRVB#unselectedButtonAnimation") { unselectedButton.animateTo( unselectedButtonUiModel, if (previousIndex == count - 1) { @@ -286,7 +279,7 @@ constructor( ) } } - launch { + launchTraced("VDRVB#bindButtons") { delay(CLOSE_DRAWER_DELAY) bindButtons(viewModel, uiModel, onAnimationEnd, isAnimated = true) } @@ -395,7 +388,7 @@ constructor( roundnessAnimation.minimumVisibleChange = BUTTON_MIN_VISIBLE_CHANGE colorAnimation.minimumVisibleChange = BUTTON_MIN_VISIBLE_CHANGE coroutineScope { - launch { + launchTraced("VDRVB#colorAnimation") { colorAnimation.suspendAnimate { value -> val currentIconColor = rgbEvaluator.evaluate( @@ -423,14 +416,9 @@ constructor( } } - private fun View.applyCorners(fullRadius: Int, diff: Int, progress: Float, isBottom: Boolean) { + private fun View.applyCorners(fullRadius: Int, diff: Int, progress: Float) { val radius = fullRadius - progress * diff - (background as GradientDrawable).cornerRadii = - if (isBottom) { - floatArrayOf(0F, 0F, 0F, 0F, radius, radius, radius, radius) - } else { - FloatArray(8) { radius } - } + (background as GradientDrawable).cornerRadius = radius background.invalidateSelf() } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt index 54f04e274c03..cf9136b4daf4 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/settings/ui/binder/VolumeDialogSettingsButtonViewBinder.kt @@ -18,6 +18,8 @@ package com.android.systemui.volume.dialog.settings.ui.binder import android.view.View import android.widget.ImageButton +import com.android.app.tracing.coroutines.launchInTraced +import com.android.app.tracing.coroutines.launchTraced import com.android.systemui.res.R import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope import com.android.systemui.volume.dialog.settings.ui.viewmodel.VolumeDialogSettingsButtonViewModel @@ -25,9 +27,7 @@ import com.android.systemui.volume.dialog.ui.binder.ViewBinder import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch @VolumeDialogScope class VolumeDialogSettingsButtonViewBinder @@ -39,12 +39,12 @@ constructor( override fun CoroutineScope.bind(view: View) { val button = view.requireViewById<ImageButton>(R.id.volume_dialog_settings) - launch { dialogViewModel.addTouchableBounds(button) } + launchTraced("VDSBVB#addTouchableBounds") { dialogViewModel.addTouchableBounds(button) } viewModel.isVisible .onEach { isVisible -> button.visibility = if (isVisible) View.VISIBLE else View.GONE } - .launchIn(this) + .launchInTraced("VDSBVB#isVisible", this) - viewModel.icon.onEach { button.setImageDrawable(it) }.launchIn(this) + viewModel.icon.onEach { button.setImageDrawable(it) }.launchInTraced("VDSBVB#icon", this) button.setOnClickListener { viewModel.onButtonClicked() } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogOverscrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogOverscrollViewBinder.kt index 38feb69aad7b..c361b50dd4ee 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogOverscrollViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogOverscrollViewBinder.kt @@ -20,12 +20,12 @@ import android.view.View import androidx.dynamicanimation.animation.FloatValueHolder import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce +import com.android.app.tracing.coroutines.launchInTraced import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel.OverscrollEventModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @VolumeDialogSliderScope @@ -62,7 +62,7 @@ constructor(private val viewModel: VolumeDialogOverscrollViewModel) { } } } - .launchIn(this) + .launchInTraced("VDOVB#overscrollEvent", this) } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt index 2c9ee54878e5..1c0fabea6d63 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSliderViewBinder.kt @@ -39,7 +39,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -99,7 +98,6 @@ private fun VolumeDialogSlider( hapticsViewModelFactory: SliderHapticsViewModel.Factory?, modifier: Modifier = Modifier, ) { - val coroutineScope = rememberCoroutineScope() val colors = SliderDefaults.colors( thumbColor = MaterialTheme.colorScheme.primary, diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt index 0d970e5117c2..527f8bdeda91 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt @@ -21,6 +21,8 @@ import android.view.View import android.view.ViewGroup import androidx.annotation.LayoutRes import androidx.compose.ui.util.fastForEachIndexed +import com.android.app.tracing.coroutines.launchInTraced +import com.android.app.tracing.coroutines.launchTraced import com.android.systemui.res.R import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent @@ -29,9 +31,7 @@ import com.android.systemui.volume.dialog.ui.binder.ViewBinder import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch @VolumeDialogScope class VolumeDialogSlidersViewBinder @@ -50,7 +50,9 @@ constructor( val bottomSection: View = view.requireViewById(R.id.volume_dialog_bottom_section_container) val topSection: View = view.requireViewById(R.id.volume_dialog_top_section_container) - launch { dialogViewModel.addTouchableBounds(mainSliderContainer, floatingSlidersContainer) } + launchTraced("VDSVB#addTouchableBounds") { + dialogViewModel.addTouchableBounds(mainSliderContainer, floatingSlidersContainer) + } viewModel.sliders .onEach { uiModel -> bindSlider( @@ -69,7 +71,7 @@ constructor( bindSlider(sliderComponent, sliderContainer, arrayOf(sliderContainer)) } } - .launchIn(this) + .launchInTraced("VDSVB#sliders", this) } private fun CoroutineScope.bindSlider( diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt index 98042d5022f9..0c10aaa57a05 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt @@ -17,18 +17,22 @@ package com.android.systemui.volume.dialog.ui.binder import android.app.Dialog +import android.content.Context import android.view.View +import android.view.ViewGroup import android.view.ViewTreeObserver import android.view.WindowInsets import androidx.compose.ui.util.lerp -import androidx.constraintlayout.motion.widget.MotionLayout import androidx.core.view.updatePadding import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.FloatValueHolder import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce +import com.android.app.tracing.coroutines.launchInTraced +import com.android.app.tracing.coroutines.launchTraced import com.android.internal.view.RotationPolicy import com.android.systemui.common.ui.view.onApplyWindowInsets +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.res.R import com.android.systemui.util.kotlin.awaitCancellationThenDispose import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope @@ -43,11 +47,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.scan -import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine private const val SPRING_STIFFNESS = 700f @@ -63,32 +65,43 @@ private const val ANIMATION_MINIMUM_VISIBLE_CHANGE = 0.01f class VolumeDialogViewBinder @Inject constructor( + @Application context: Context, private val viewModel: VolumeDialogViewModel, private val jankListenerFactory: JankListenerFactory, private val tracer: VolumeTracer, private val viewBinders: List<@JvmSuppressWildcards ViewBinder>, ) { + private val halfOpenedOffsetPx: Float = + context.resources.getDimensionPixelSize(R.dimen.volume_dialog_half_opened_offset).toFloat() + fun CoroutineScope.bind(dialog: Dialog) { val insets: MutableStateFlow<WindowInsets> = MutableStateFlow(WindowInsets.Builder().build()) // Root view of the Volume Dialog. - val root: MotionLayout = dialog.requireViewById(R.id.volume_dialog) + val root: ViewGroup = dialog.requireViewById(R.id.volume_dialog) animateVisibility(root, dialog, viewModel.dialogVisibilityModel) - viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this) - viewModel.motionState - .scan(0) { acc, motionState -> + viewModel.dialogTitle + .onEach { dialog.window?.setTitle(it) } + .launchInTraced("VDVB#dialogTitle", this) + viewModel.isHalfOpened + .scan<Boolean, Boolean?>(null) { acc, isHalfOpened -> // don't animate the initial state - root.transitionToState(motionState, animate = acc != 0) - acc + 1 + root.applyVerticalOffset( + offsetPx = if (isHalfOpened) halfOpenedOffsetPx else 0f, + shouldAnimate = acc != null, + ) + isHalfOpened } - .launchIn(this) + .launchInTraced("VDVB#isHalfOpened", this) - launch { root.viewTreeObserver.listenToComputeInternalInsets() } + launchTraced("VDVB#viewTreeObserver") { + root.viewTreeObserver.listenToComputeInternalInsets() + } - launch { + launchTraced("VDVB#insets") { root .onApplyWindowInsets { v, newInsets -> val insetsValues = newInsets.getInsets(WindowInsets.Type.displayCutout()) @@ -135,7 +148,7 @@ constructor( junkListener?.let(animation::removeUpdateListener) junkListener = jankListenerFactory.show(view).also(animation::addUpdateListener) - animation.suspendAnimate(FRACTION_SHOW) + animation.animateToFinalPosition(FRACTION_SHOW) } is VolumeDialogVisibilityModel.Dismissed -> { tracer.traceVisibilityEnd(it) @@ -150,7 +163,7 @@ constructor( } } } - .launchIn(this) + .launchInTraced("VDVB#visibilityModel", this) } /** @@ -180,11 +193,11 @@ constructor( continuation.invokeOnCancellation { removeOnComputeInternalInsetsListener(listener) } } - private fun MotionLayout.transitionToState(newState: Int, animate: Boolean) { - if (animate) { - transitionToState(newState) - } else { - jumpToState(newState) + private suspend fun View.applyVerticalOffset(offsetPx: Float, shouldAnimate: Boolean) { + if (!shouldAnimate) { + translationY = offsetPx + return } + animate().setDuration(150).translationY(offsetPx).suspendAnimate() } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt index e47b53177189..8bfbc36b1423 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt @@ -56,18 +56,14 @@ constructor( configurationController: ConfigurationController, ) { - val motionState: Flow<Int> = + val isHalfOpened: Flow<Boolean> = combine( devicePostureController.devicePosture(), configurationController.onConfigChanged.onStart { emit(context.resources.configuration) }, ) { devicePosture, configuration -> - if (shouldOffsetVolumeDialog(devicePosture, configuration)) { - R.id.volume_dialog_half_folded_constraint_set - } else { - R.id.volume_dialog_constraint_set - } + shouldOffsetVolumeDialog(devicePosture, configuration) } val dialogVisibilityModel: Flow<VolumeDialogVisibilityModel> = dialogVisibilityInteractor.dialogVisibility diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt index ec74f4f47bc9..300a7e070b6c 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/NoopWallpaperRepository.kt @@ -17,6 +17,8 @@ package com.android.systemui.wallpapers.data.repository import android.app.WallpaperInfo +import android.graphics.PointF +import android.graphics.RectF import android.view.View import com.android.systemui.dagger.SysUISingleton import javax.inject.Inject @@ -37,4 +39,8 @@ class NoopWallpaperRepository @Inject constructor() : WallpaperRepository { override val wallpaperSupportsAmbientMode = flowOf(false) override var rootView: View? = null override val shouldSendFocalArea: StateFlow<Boolean> = MutableStateFlow(false).asStateFlow() + + override fun sendLockScreenLayoutChangeCommand(wallpaperFocalAreaBounds: RectF) {} + + override fun sendTapCommand(tapPosition: PointF) {} } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt index 2c3491b06a90..974468c16578 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperFocalAreaRepository.kt @@ -33,7 +33,8 @@ interface WallpaperFocalAreaRepository { val wallpaperFocalAreaBounds: StateFlow<RectF> - val wallpaperFocalAreaTapPosition: StateFlow<PointF> + /** It will be true when wallpaper requires focal area info. */ + val hasFocalArea: StateFlow<Boolean> /** top of notifications without bcsmartspace in small clock settings */ val notificationDefaultTop: StateFlow<Float> @@ -51,7 +52,9 @@ interface WallpaperFocalAreaRepository { } @SysUISingleton -class WallpaperFocalAreaRepositoryImpl @Inject constructor() : WallpaperFocalAreaRepository { +class WallpaperFocalAreaRepositoryImpl +@Inject +constructor(val wallpaperRepository: WallpaperRepository) : WallpaperFocalAreaRepository { private val _shortcutAbsoluteTop = MutableStateFlow(0F) override val shortcutAbsoluteTop = _shortcutAbsoluteTop.asStateFlow() @@ -63,13 +66,11 @@ class WallpaperFocalAreaRepositoryImpl @Inject constructor() : WallpaperFocalAre override val wallpaperFocalAreaBounds: StateFlow<RectF> = _wallpaperFocalAreaBounds.asStateFlow() - private val _wallpaperFocalAreaTapPosition = MutableStateFlow(PointF(0F, 0F)) - override val wallpaperFocalAreaTapPosition: StateFlow<PointF> = - _wallpaperFocalAreaTapPosition.asStateFlow() - private val _notificationDefaultTop = MutableStateFlow(0F) override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow() + override val hasFocalArea = wallpaperRepository.shouldSendFocalArea + override fun setShortcutAbsoluteTop(top: Float) { _shortcutAbsoluteTop.value = top } @@ -84,9 +85,10 @@ class WallpaperFocalAreaRepositoryImpl @Inject constructor() : WallpaperFocalAre override fun setWallpaperFocalAreaBounds(bounds: RectF) { _wallpaperFocalAreaBounds.value = bounds + wallpaperRepository.sendLockScreenLayoutChangeCommand(bounds) } - override fun setTapPosition(point: PointF) { - _wallpaperFocalAreaTapPosition.value = point + override fun setTapPosition(tapPosition: PointF) { + wallpaperRepository.sendTapCommand(tapPosition) } } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt index a55f76b333d9..b07342c4c76d 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/data/repository/WallpaperRepository.kt @@ -21,22 +21,18 @@ import android.app.WallpaperManager import android.content.Context import android.content.Intent import android.content.IntentFilter +import android.graphics.PointF +import android.graphics.RectF import android.os.Bundle import android.os.UserHandle import android.provider.Settings +import android.util.Log import android.view.View -import androidx.annotation.VisibleForTesting -import com.android.app.tracing.coroutines.launchTraced as launch import com.android.internal.R import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.shared.model.Edge -import com.android.systemui.keyguard.shared.model.KeyguardState -import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.res.R as SysUIR -import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shared.Flags.ambientAod import com.android.systemui.shared.Flags.extendedWallpaperEffects import com.android.systemui.user.data.model.SelectedUserModel @@ -48,7 +44,6 @@ import com.android.systemui.utils.coroutines.flow.mapLatestConflated import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -76,6 +71,10 @@ interface WallpaperRepository { /** some wallpapers require bounds to be sent from keyguard */ val shouldSendFocalArea: StateFlow<Boolean> + + fun sendLockScreenLayoutChangeCommand(wallpaperFocalAreaBounds: RectF) + + fun sendTapCommand(tapPosition: PointF) } @SysUISingleton @@ -86,10 +85,8 @@ constructor( @Background private val bgDispatcher: CoroutineDispatcher, broadcastDispatcher: BroadcastDispatcher, userRepository: UserRepository, - wallpaperFocalAreaRepository: WallpaperFocalAreaRepository, private val wallpaperManager: WallpaperManager, private val context: Context, - keyguardTransitionInteractor: KeyguardTransitionInteractor, private val secureSettings: SecureSettings, ) : WallpaperRepository { private val wallpaperChanged: Flow<Unit> = @@ -109,9 +106,6 @@ constructor( // Only update the wallpaper status once the user selection has finished. .filter { it.selectionStatus == SelectionStatus.SELECTION_COMPLETE } - @VisibleForTesting var sendLockscreenLayoutJob: Job? = null - @VisibleForTesting var sendTapInShapeEffectsJob: Job? = null - override val wallpaperInfo: StateFlow<WallpaperInfo?> = if (!wallpaperManager.isWallpaperSupported) { MutableStateFlow(null).asStateFlow() @@ -143,77 +137,45 @@ constructor( override var rootView: View? = null + override fun sendLockScreenLayoutChangeCommand(wallpaperFocalAreaBounds: RectF) { + if (DEBUG) { + Log.d(TAG, "sendLockScreenLayoutChangeCommand $wallpaperFocalAreaBounds") + } + wallpaperManager.sendWallpaperCommand( + /* windowToken = */ rootView?.windowToken, + /* action = */ WallpaperManager.COMMAND_LOCKSCREEN_LAYOUT_CHANGED, + /* x = */ 0, + /* y = */ 0, + /* z = */ 0, + /* extras = */ Bundle().apply { + putFloat("wallpaperFocalAreaLeft", wallpaperFocalAreaBounds.left) + putFloat("wallpaperFocalAreaRight", wallpaperFocalAreaBounds.right) + putFloat("wallpaperFocalAreaTop", wallpaperFocalAreaBounds.top) + putFloat("wallpaperFocalAreaBottom", wallpaperFocalAreaBounds.bottom) + }, + ) + } + + override fun sendTapCommand(tapPosition: PointF) { + if (DEBUG) { + Log.d(TAG, "sendTapCommand $tapPosition") + } + + wallpaperManager.sendWallpaperCommand( + /* windowToken = */ rootView?.windowToken, + /* action = */ WallpaperManager.COMMAND_LOCKSCREEN_TAP, + /* x = */ tapPosition.x.toInt(), + /* y = */ tapPosition.y.toInt(), + /* z = */ 0, + /* extras = */ Bundle(), + ) + } + override val shouldSendFocalArea = wallpaperInfo .map { val focalAreaTarget = context.resources.getString(SysUIR.string.focal_area_target) val shouldSendNotificationLayout = it?.component?.className == focalAreaTarget - if (shouldSendNotificationLayout) { - sendLockscreenLayoutJob = - scope.launch { - combine( - wallpaperFocalAreaRepository.wallpaperFocalAreaBounds, - keyguardTransitionInteractor - .transition( - edge = Edge.create(to = Scenes.Lockscreen), - edgeWithoutSceneContainer = - Edge.create(to = KeyguardState.LOCKSCREEN), - ) - .filter { transitionStep -> - transitionStep.transitionState == - TransitionState.STARTED - }, - ::Pair, - ) - .map { (bounds, _) -> bounds } - .collect { wallpaperFocalAreaBounds -> - wallpaperManager.sendWallpaperCommand( - /* windowToken = */ rootView?.windowToken, - /* action = */ WallpaperManager - .COMMAND_LOCKSCREEN_LAYOUT_CHANGED, - /* x = */ 0, - /* y = */ 0, - /* z = */ 0, - /* extras = */ Bundle().apply { - putFloat( - "wallpaperFocalAreaLeft", - wallpaperFocalAreaBounds.left, - ) - putFloat( - "wallpaperFocalAreaRight", - wallpaperFocalAreaBounds.right, - ) - putFloat( - "wallpaperFocalAreaTop", - wallpaperFocalAreaBounds.top, - ) - putFloat( - "wallpaperFocalAreaBottom", - wallpaperFocalAreaBounds.bottom, - ) - }, - ) - } - } - - sendTapInShapeEffectsJob = - scope.launch { - wallpaperFocalAreaRepository.wallpaperFocalAreaTapPosition.collect { - wallpaperFocalAreaTapPosition -> - wallpaperManager.sendWallpaperCommand( - /* windowToken = */ rootView?.windowToken, - /* action = */ WallpaperManager.COMMAND_LOCKSCREEN_TAP, - /* x = */ wallpaperFocalAreaTapPosition.x.toInt(), - /* y = */ wallpaperFocalAreaTapPosition.y.toInt(), - /* z = */ 0, - /* extras = */ null, - ) - } - } - } else { - sendLockscreenLayoutJob?.cancel() - sendTapInShapeEffectsJob?.cancel() - } shouldSendNotificationLayout } .stateIn( @@ -227,4 +189,9 @@ constructor( wallpaperManager.getWallpaperInfoForUser(selectedUser.userInfo.id) } } + + companion object { + private val TAG = WallpaperRepositoryImpl::class.simpleName + private val DEBUG = true + } } diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt index 9b0f8280cab2..09c6cdf0ce22 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt @@ -24,31 +24,25 @@ import android.util.Log import android.util.TypedValue import com.android.app.animation.MathUtils import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.res.R import com.android.systemui.shade.data.repository.ShadeRepository -import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.wallpapers.data.repository.WallpaperFocalAreaRepository -import com.android.systemui.wallpapers.data.repository.WallpaperRepository import javax.inject.Inject import kotlin.math.min -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter @SysUISingleton class WallpaperFocalAreaInteractor @Inject constructor( - @Application private val applicationScope: CoroutineScope, private val context: Context, private val wallpaperFocalAreaRepository: WallpaperFocalAreaRepository, shadeRepository: ShadeRepository, - activeNotificationsInteractor: ActiveNotificationsInteractor, - val wallpaperRepository: WallpaperRepository, ) { - val hasFocalArea = wallpaperRepository.shouldSendFocalArea + val hasFocalArea = wallpaperFocalAreaRepository.hasFocalArea val wallpaperFocalAreaBounds: Flow<RectF> = combine( @@ -126,6 +120,8 @@ constructor( val bottom = scaledBounds.bottom - scaledBottomMargin RectF(left, top, right, bottom).also { Log.d(TAG, "Focal area changes to $it") } } + // Make sure a valid rec + .filter { it.width() >= 0 && it.height() >= 0 } .distinctUntilChanged() fun setFocalAreaBounds(bounds: RectF) { diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt index 70a97d473c49..4cd49d03ad36 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt @@ -17,15 +17,41 @@ package com.android.systemui.wallpapers.ui.viewmodel import android.graphics.RectF +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.Edge +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.wallpapers.domain.interactor.WallpaperFocalAreaInteractor import javax.inject.Inject +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.map class WallpaperFocalAreaViewModel @Inject -constructor(private val wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor) { +constructor( + private val wallpaperFocalAreaInteractor: WallpaperFocalAreaInteractor, + val keyguardTransitionInteractor: KeyguardTransitionInteractor, +) { val hasFocalArea = wallpaperFocalAreaInteractor.hasFocalArea - val wallpaperFocalAreaBounds = wallpaperFocalAreaInteractor.wallpaperFocalAreaBounds + val wallpaperFocalAreaBounds = + combine( + wallpaperFocalAreaInteractor.wallpaperFocalAreaBounds, + keyguardTransitionInteractor + .transition( + edge = Edge.create(to = Scenes.Lockscreen), + edgeWithoutSceneContainer = Edge.create(to = KeyguardState.LOCKSCREEN), + ) + .filter { transitionStep -> + // Should not filter by TransitionState.STARTED, it may race with + // wakingup command, causing layout change command not be received. + transitionStep.transitionState == TransitionState.FINISHED + }, + ::Pair, + ) + .map { (bounds, _) -> bounds } fun setFocalAreaBounds(bounds: RectF) { wallpaperFocalAreaInteractor.setFocalAreaBounds(bounds) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt index bfc5361b6129..f04fc86d7230 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModelTest.kt @@ -43,6 +43,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.volume.domain.interactor.audioModeInteractor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableSharedFlow @@ -146,6 +147,7 @@ class BluetoothDetailsContentViewModelTest : SysuiTestCase() { ) ), kosmos.audioSharingInteractor, + kosmos.audioModeInteractor, kosmos.audioSharingButtonViewModelFactory, bluetoothDeviceMetadataInteractor, mDialogTransitionAnimator, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt index 0aa5199cb20e..7c8822bc11ec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt @@ -18,7 +18,6 @@ package com.android.systemui.bluetooth.qsdialog import android.bluetooth.BluetoothDevice import android.graphics.drawable.Drawable -import android.media.AudioManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.TestableLooper @@ -61,8 +60,6 @@ class DeviceItemFactoryTest : SysuiTestCase() { private val connectedDeviceItemFactory = ConnectedDeviceItemFactory() private val savedDeviceItemFactory = SavedDeviceItemFactory() - private val audioManager = context.getSystemService(AudioManager::class.java)!! - @Before fun setup() { mockitoSession = @@ -132,7 +129,12 @@ class DeviceItemFactoryTest : SysuiTestCase() { fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_flagOff_returnsFalse() { assertThat( AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager) - .isFilterMatched(context, cachedDevice, audioManager, false) + .isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + audioSharingAvailable = false, + ) ) .isFalse() } @@ -143,7 +145,12 @@ class DeviceItemFactoryTest : SysuiTestCase() { assertThat( AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager) - .isFilterMatched(context, cachedDevice, audioManager, true) + .isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + audioSharingAvailable = true, + ) ) .isFalse() } @@ -157,7 +164,26 @@ class DeviceItemFactoryTest : SysuiTestCase() { assertThat( AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager) - .isFilterMatched(context, cachedDevice, audioManager, true) + .isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + audioSharingAvailable = true, + ) + ) + .isFalse() + } + + @Test + fun testAvailableAudioSharingMediaDeviceItemFactory_isFilterMatched_inCall_false() { + assertThat( + AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager) + .isFilterMatched( + context, + cachedDevice, + isOngoingCall = true, + audioSharingAvailable = true, + ) ) .isFalse() } @@ -171,7 +197,12 @@ class DeviceItemFactoryTest : SysuiTestCase() { assertThat( AvailableAudioSharingMediaDeviceItemFactory(localBluetoothManager) - .isFilterMatched(context, cachedDevice, audioManager, true) + .isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + audioSharingAvailable = true, + ) ) .isTrue() } @@ -182,7 +213,9 @@ class DeviceItemFactoryTest : SysuiTestCase() { `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) `when`(cachedDevice.isConnected).thenReturn(false) - assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false) + ) .isTrue() } @@ -192,7 +225,9 @@ class DeviceItemFactoryTest : SysuiTestCase() { `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) `when`(cachedDevice.isConnected).thenReturn(true) - assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false) + ) .isFalse() } @@ -201,7 +236,9 @@ class DeviceItemFactoryTest : SysuiTestCase() { fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() { `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE) - assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false) + ) .isFalse() } @@ -211,7 +248,9 @@ class DeviceItemFactoryTest : SysuiTestCase() { `when`(cachedDevice.device).thenReturn(bluetoothDevice) `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true) - assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false) + ) .isFalse() } @@ -223,7 +262,9 @@ class DeviceItemFactoryTest : SysuiTestCase() { `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) `when`(cachedDevice.isConnected).thenReturn(false) - assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false) + ) .isTrue() } @@ -235,7 +276,9 @@ class DeviceItemFactoryTest : SysuiTestCase() { `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) `when`(cachedDevice.isConnected).thenReturn(true) - assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false) + ) .isFalse() } @@ -244,14 +287,26 @@ class DeviceItemFactoryTest : SysuiTestCase() { fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() { `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(true) - assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + connectedDeviceItemFactory.isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + ) + ) .isTrue() } @Test @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) fun testConnectedFactory_isFilterMatched_notConnected_returnsFalse() { - assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + connectedDeviceItemFactory.isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + ) + ) .isFalse() } @@ -261,7 +316,13 @@ class DeviceItemFactoryTest : SysuiTestCase() { `when`(cachedDevice.device).thenReturn(bluetoothDevice) `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true) - assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + connectedDeviceItemFactory.isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + ) + ) .isFalse() } @@ -272,7 +333,13 @@ class DeviceItemFactoryTest : SysuiTestCase() { `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false) `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(true) - assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + connectedDeviceItemFactory.isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + ) + ) .isTrue() } @@ -283,7 +350,13 @@ class DeviceItemFactoryTest : SysuiTestCase() { `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false) `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(false) - assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + assertThat( + connectedDeviceItemFactory.isFilterMatched( + context, + cachedDevice, + isOngoingCall = false, + ) + ) .isFalse() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt index 42dc50d77d05..943b89aa10f3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemInteractorTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.testKosmos import com.android.systemui.util.time.FakeSystemClock +import com.android.systemui.volume.domain.interactor.audioModeInteractor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.test.TestScope @@ -102,7 +103,6 @@ class DeviceItemInteractorTest : SysuiTestCase() { DeviceItemInteractor( bluetoothTileDialogRepository, kosmos.audioSharingInteractor, - audioManager, adapter, localBluetoothManager, fakeSystemClock, @@ -111,6 +111,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { emptyList(), testScope.backgroundScope, dispatcher, + kosmos.audioModeInteractor, ) val latest by collectLastValue(interactor.deviceItemUpdate) @@ -130,7 +131,6 @@ class DeviceItemInteractorTest : SysuiTestCase() { DeviceItemInteractor( bluetoothTileDialogRepository, kosmos.audioSharingInteractor, - audioManager, adapter, localBluetoothManager, fakeSystemClock, @@ -139,6 +139,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { emptyList(), testScope.backgroundScope, dispatcher, + kosmos.audioModeInteractor, ) val latest by collectLastValue(interactor.deviceItemUpdate) @@ -158,7 +159,6 @@ class DeviceItemInteractorTest : SysuiTestCase() { DeviceItemInteractor( bluetoothTileDialogRepository, kosmos.audioSharingInteractor, - audioManager, adapter, localBluetoothManager, fakeSystemClock, @@ -167,6 +167,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { emptyList(), testScope.backgroundScope, dispatcher, + kosmos.audioModeInteractor, ) val latest by collectLastValue(interactor.deviceItemUpdate) @@ -186,7 +187,6 @@ class DeviceItemInteractorTest : SysuiTestCase() { DeviceItemInteractor( bluetoothTileDialogRepository, kosmos.audioSharingInteractor, - audioManager, adapter, localBluetoothManager, fakeSystemClock, @@ -198,6 +198,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { emptyList(), testScope.backgroundScope, dispatcher, + kosmos.audioModeInteractor, ) val latest by collectLastValue(interactor.deviceItemUpdate) @@ -217,7 +218,6 @@ class DeviceItemInteractorTest : SysuiTestCase() { DeviceItemInteractor( bluetoothTileDialogRepository, kosmos.audioSharingInteractor, - audioManager, adapter, localBluetoothManager, fakeSystemClock, @@ -238,6 +238,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { ), testScope.backgroundScope, dispatcher, + kosmos.audioModeInteractor, ) `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE) `when`(deviceItem2.type).thenReturn(DeviceItemType.SAVED_BLUETOOTH_DEVICE) @@ -259,7 +260,6 @@ class DeviceItemInteractorTest : SysuiTestCase() { DeviceItemInteractor( bluetoothTileDialogRepository, kosmos.audioSharingInteractor, - audioManager, adapter, localBluetoothManager, fakeSystemClock, @@ -277,6 +277,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { listOf(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE), testScope.backgroundScope, dispatcher, + kosmos.audioModeInteractor, ) `when`(deviceItem1.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE) `when`(deviceItem2.type).thenReturn(DeviceItemType.CONNECTED_BLUETOOTH_DEVICE) @@ -300,7 +301,6 @@ class DeviceItemInteractorTest : SysuiTestCase() { DeviceItemInteractor( bluetoothTileDialogRepository, kosmos.audioSharingInteractor, - audioManager, adapter, localBluetoothManager, fakeSystemClock, @@ -309,6 +309,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { emptyList(), testScope.backgroundScope, dispatcher, + kosmos.audioModeInteractor, ) val latest by collectLastValue(interactor.deviceItemUpdate) val latestShowSeeAll by collectLastValue(interactor.showSeeAllUpdate) @@ -327,7 +328,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { override fun isFilterMatched( context: Context, cachedDevice: CachedBluetoothDevice, - audioManager: AudioManager, + isOngoingCall: Boolean, audioSharingAvailable: Boolean, ) = isFilterMatchFunc(cachedDevice) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt index a0be02f1ef7e..bd4c5f50eee7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt @@ -43,6 +43,7 @@ import com.android.systemui.qs.panels.ui.compose.infinitegrid.DefaultEditTileGri import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.shared.model.TileCategory +import com.android.systemui.res.R import com.google.common.truth.Truth.assertThat import org.junit.Rule import org.junit.Test @@ -85,7 +86,9 @@ class ResizingTest : SysuiTestCase() { composeRule .onNodeWithContentDescription("tileA") - .performCustomAccessibilityActionWithLabel("Toggle size") + .performCustomAccessibilityActionWithLabel( + context.getString(R.string.accessibility_qs_edit_toggle_tile_size_action) + ) assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2) } @@ -101,7 +104,9 @@ class ResizingTest : SysuiTestCase() { composeRule .onNodeWithContentDescription("tileD_large") - .performCustomAccessibilityActionWithLabel("Toggle size") + .performCustomAccessibilityActionWithLabel( + context.getString(R.string.accessibility_qs_edit_toggle_tile_size_action) + ) assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt index 944604f94ce4..ae8b52aa6553 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt @@ -18,7 +18,7 @@ package com.android.systemui.shade import android.graphics.Insets import android.graphics.Rect -import android.os.PowerManager +import android.os.powerManager import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner @@ -32,7 +32,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.test.filters.SmallTest import com.android.compose.animation.scene.SceneKey -import com.android.systemui.Flags +import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 import com.android.systemui.Flags.FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX import com.android.systemui.SysuiTestCase @@ -40,7 +40,6 @@ import com.android.systemui.ambient.touch.TouchHandler import com.android.systemui.ambient.touch.TouchMonitor import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository -import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.communalSettingsInteractor @@ -58,8 +57,10 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.controller.keyguardMediaController import com.android.systemui.res.R @@ -69,8 +70,8 @@ import com.android.systemui.statusbar.lockscreen.lockscreenSmartspaceController import com.android.systemui.statusbar.notification.stack.notificationStackScrollLayoutController import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.launch -import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Assert.assertThrows @@ -89,33 +90,23 @@ import org.mockito.kotlin.whenever @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest +@EnableFlags(FLAG_COMMUNAL_HUB) class GlanceableHubContainerControllerTest : SysuiTestCase() { - private val kosmos: Kosmos = - testKosmos().apply { - // UnconfinedTestDispatcher makes testing simpler due to CommunalInteractor flows using - // SharedFlow - testDispatcher = UnconfinedTestDispatcher() - } + private val kosmos: Kosmos = testKosmos().useUnconfinedTestDispatcher() - private var communalViewModel = mock<CommunalViewModel>() - private var powerManager = mock<PowerManager>() - private var touchMonitor = mock<TouchMonitor>() - private var communalColors = mock<CommunalColors>() - private var communalContent = mock<CommunalContent>() - private lateinit var ambientTouchComponentFactory: AmbientTouchComponent.Factory + private val swipeToHubEnabled = MutableStateFlow(false) + private val mockCommunalViewModel = + mock<CommunalViewModel> { on { swipeToHubEnabled } doReturn swipeToHubEnabled } + private val touchMonitor = mock<TouchMonitor>() private lateinit var parentView: FrameLayout private lateinit var containerView: View - private lateinit var testableLooper: TestableLooper - - private lateinit var communalRepository: FakeCommunalSceneRepository - private lateinit var underTest: GlanceableHubContainerController - @Before - fun setUp() { - communalRepository = kosmos.fakeCommunalSceneRepository + private val Kosmos.testableLooper by + Kosmos.Fixture { TestableLooper.get(this@GlanceableHubContainerControllerTest) } - ambientTouchComponentFactory = + private val Kosmos.ambientTouchComponentFactory by + Kosmos.Fixture { object : AmbientTouchComponent.Factory { override fun create( lifecycleOwner: LifecycleOwner, @@ -126,50 +117,39 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { override fun getTouchMonitor(): TouchMonitor = touchMonitor } } + } - with(kosmos) { - underTest = - GlanceableHubContainerController( - communalInteractor, - communalSettingsInteractor, - communalViewModel, - keyguardInteractor, - keyguardTransitionInteractor, - shadeInteractor, - powerManager, - communalColors, - ambientTouchComponentFactory, - communalContent, - sceneDataSourceDelegator, - notificationStackScrollLayoutController, - keyguardMediaController, - lockscreenSmartspaceController, - logcatLogBuffer("GlanceableHubContainerControllerTest"), - ) - - // Make below last notification true by default or else touches will be ignored by - // default when the hub is not showing. - whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any())) - .thenReturn(true) + private val Kosmos.underTest by + Kosmos.Fixture { + GlanceableHubContainerController( + communalInteractor, + communalSettingsInteractor, + mockCommunalViewModel, + keyguardInteractor, + keyguardTransitionInteractor, + shadeInteractor, + powerManager, + mock<CommunalColors>(), + ambientTouchComponentFactory, + mock<CommunalContent>(), + sceneDataSourceDelegator, + notificationStackScrollLayoutController, + keyguardMediaController, + lockscreenSmartspaceController, + logcatLogBuffer("GlanceableHubContainerControllerTest"), + ) } - testableLooper = TestableLooper.get(this) + @Before + fun setUp() { overrideResource(R.dimen.communal_right_edge_swipe_region_width, RIGHT_SWIPE_REGION_WIDTH) overrideResource(R.dimen.communal_top_edge_swipe_region_height, TOP_SWIPE_REGION_WIDTH) overrideResource( R.dimen.communal_bottom_edge_swipe_region_height, BOTTOM_SWIPE_REGION_WIDTH, ) - - // Make communal available so that communalInteractor.desiredScene accurately reflects - // scene changes instead of just returning Blank. - mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB) - with(kosmos.testScope) { - launch { kosmos.setCommunalAvailable(true) } - testScheduler.runCurrent() - } - - initAndAttachContainerView() + runBlocking { kosmos.setCommunalAvailable(true) } + kosmos.initAndAttachContainerView() } @After @@ -179,606 +159,531 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { @Test fun initView_calledTwice_throwsException() = - with(kosmos) { - testScope.runTest { - underTest = - GlanceableHubContainerController( - communalInteractor, - kosmos.communalSettingsInteractor, - communalViewModel, - keyguardInteractor, - kosmos.keyguardTransitionInteractor, - shadeInteractor, - powerManager, - communalColors, - ambientTouchComponentFactory, - communalContent, - kosmos.sceneDataSourceDelegator, - kosmos.notificationStackScrollLayoutController, - kosmos.keyguardMediaController, - kosmos.lockscreenSmartspaceController, - logcatLogBuffer("GlanceableHubContainerControllerTest"), - ) + kosmos.runTest { + val controller = + GlanceableHubContainerController( + communalInteractor, + communalSettingsInteractor, + mockCommunalViewModel, + keyguardInteractor, + keyguardTransitionInteractor, + shadeInteractor, + powerManager, + mock<CommunalColors>(), + ambientTouchComponentFactory, + mock<CommunalContent>(), + sceneDataSourceDelegator, + notificationStackScrollLayoutController, + keyguardMediaController, + lockscreenSmartspaceController, + logcatLogBuffer("GlanceableHubContainerControllerTest"), + ) - // First call succeeds. - underTest.initView(context) + // First call succeeds. + controller.initView(context) - // Second call throws. - assertThrows(RuntimeException::class.java) { underTest.initView(context) } - } + // Second call throws. + assertThrows(RuntimeException::class.java) { controller.initView(context) } } @Test fun lifecycle_initializedAfterConstruction() = - with(kosmos) { - val underTest = + kosmos.runTest { + val controller = GlanceableHubContainerController( communalInteractor, - kosmos.communalSettingsInteractor, - communalViewModel, + communalSettingsInteractor, + mockCommunalViewModel, keyguardInteractor, - kosmos.keyguardTransitionInteractor, + keyguardTransitionInteractor, shadeInteractor, powerManager, - communalColors, + mock<CommunalColors>(), ambientTouchComponentFactory, - communalContent, - kosmos.sceneDataSourceDelegator, - kosmos.notificationStackScrollLayoutController, - kosmos.keyguardMediaController, - kosmos.lockscreenSmartspaceController, + mock<CommunalContent>(), + sceneDataSourceDelegator, + notificationStackScrollLayoutController, + keyguardMediaController, + lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest"), ) - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED) + assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED) } @Test fun lifecycle_createdAfterViewCreated() = - with(kosmos) { - val underTest = + kosmos.runTest { + val controller = GlanceableHubContainerController( communalInteractor, - kosmos.communalSettingsInteractor, - communalViewModel, + communalSettingsInteractor, + mockCommunalViewModel, keyguardInteractor, - kosmos.keyguardTransitionInteractor, + keyguardTransitionInteractor, shadeInteractor, powerManager, - communalColors, + mock<CommunalColors>(), ambientTouchComponentFactory, - communalContent, - kosmos.sceneDataSourceDelegator, - kosmos.notificationStackScrollLayoutController, - kosmos.keyguardMediaController, - kosmos.lockscreenSmartspaceController, + mock<CommunalContent>(), + sceneDataSourceDelegator, + notificationStackScrollLayoutController, + keyguardMediaController, + lockscreenSmartspaceController, logcatLogBuffer("GlanceableHubContainerControllerTest"), ) // Only initView without attaching a view as we don't want the flows to start collecting // yet. - underTest.initView(View(context)) + controller.initView(View(context)) - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED) + assertThat(controller.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED) } @Test - fun lifecycle_startedAfterFlowsUpdate() { - // Flows start collecting due to test setup, causing the state to advance to STARTED. - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - } + fun lifecycle_startedAfterFlowsUpdate() = + kosmos.runTest { + // Flows start collecting due to test setup, causing the state to advance to STARTED. + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) + } @Test fun lifecycle_resumedAfterCommunalShows() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED) - } + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED) } @Test fun lifecycle_startedAfterCommunalCloses() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED) + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED) - // Communal closes. - goToScene(CommunalScenes.Blank) + // Communal closes. + goToScene(CommunalScenes.Blank) - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - } + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) } @Test fun lifecycle_startedAfterPrimaryBouncerShows() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) - // Bouncer is visible. - fakeKeyguardBouncerRepository.setPrimaryShow(true) - testableLooper.processAllMessages() + // Bouncer is visible. + fakeKeyguardBouncerRepository.setPrimaryShow(true) + testableLooper.processAllMessages() - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - } + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) } @Test fun lifecycle_startedAfterAlternateBouncerShows() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) - // Bouncer is visible. - fakeKeyguardBouncerRepository.setAlternateVisible(true) - testableLooper.processAllMessages() + // Bouncer is visible. + fakeKeyguardBouncerRepository.setAlternateVisible(true) + testableLooper.processAllMessages() - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - } + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) } @Test fun lifecycle_startedWhenEditActivityShowing() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) - // Edit activity is showing. - communalInteractor.setEditActivityShowing(true) - testableLooper.processAllMessages() + // Edit activity is showing. + communalInteractor.setEditActivityShowing(true) + testableLooper.processAllMessages() - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - } + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) } @Test fun lifecycle_startedWhenEditModeTransitionStarted() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) - - // Leaving edit mode to return to the hub. - fakeKeyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.GLANCEABLE_HUB, - value = 1.0f, - transitionState = TransitionState.RUNNING, - ) + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) + + // Leaving edit mode to return to the hub. + fakeKeyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.GLANCEABLE_HUB, + value = 1.0f, + transitionState = TransitionState.RUNNING, ) - testableLooper.processAllMessages() + ) + testableLooper.processAllMessages() - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - } + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) } @Test - fun lifecycle_createdAfterDisposeView() { - // Container view disposed. - underTest.disposeView() + fun lifecycle_createdAfterDisposeView() = + kosmos.runTest { + // Container view disposed. + underTest.disposeView() - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED) - } + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.CREATED) + } @Test fun lifecycle_startedAfterShadeShows() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) - // Shade shows up. - shadeTestUtil.setQsExpansion(1.0f) - testableLooper.processAllMessages() + // Shade shows up. + shadeTestUtil.setQsExpansion(1.0f) + testableLooper.processAllMessages() - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - } + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) } @Test fun lifecycle_doesNotResumeOnUserInteractivityOnceExpanded() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) - - // Shade shows up. - shadeTestUtil.setShadeExpansion(1.0f) - testableLooper.processAllMessages() - underTest.onTouchEvent(DOWN_EVENT) - testableLooper.processAllMessages() - - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - - // Shade starts collapsing. - shadeTestUtil.setShadeExpansion(.5f) - testableLooper.processAllMessages() - underTest.onTouchEvent(DOWN_EVENT) - testableLooper.processAllMessages() - - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) - - // Shade fully collpase, and then expand should with touch interaction should now - // be resumed. - shadeTestUtil.setShadeExpansion(0f) - testableLooper.processAllMessages() - shadeTestUtil.setShadeExpansion(.5f) - testableLooper.processAllMessages() - underTest.onTouchEvent(DOWN_EVENT) - testableLooper.processAllMessages() - - assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED) - } + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) + + // Shade shows up. + shadeTestUtil.setShadeExpansion(1.0f) + testableLooper.processAllMessages() + underTest.onTouchEvent(DOWN_EVENT) + testableLooper.processAllMessages() + + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) + + // Shade starts collapsing. + shadeTestUtil.setShadeExpansion(.5f) + testableLooper.processAllMessages() + underTest.onTouchEvent(DOWN_EVENT) + testableLooper.processAllMessages() + + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.STARTED) + + // Shade fully collpase, and then expand should with touch interaction should now + // be resumed. + shadeTestUtil.setShadeExpansion(0f) + testableLooper.processAllMessages() + shadeTestUtil.setShadeExpansion(.5f) + testableLooper.processAllMessages() + underTest.onTouchEvent(DOWN_EVENT) + testableLooper.processAllMessages() + + assertThat(underTest.lifecycle.currentState).isEqualTo(Lifecycle.State.RESUMED) } @Test fun touchHandling_moveEventProcessedAfterCancel() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) - - // Touch starts and ends. - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() - assertThat(underTest.onTouchEvent(CANCEL_EVENT)).isTrue() - - // Up event is no longer processed - assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse() - - // Move event can still be processed - assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue() - assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue() - assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue() - } + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) + + // Touch starts and ends. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() + assertThat(underTest.onTouchEvent(CANCEL_EVENT)).isTrue() + + // Up event is no longer processed + assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse() + + // Move event can still be processed + assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue() + assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue() + assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue() } @Test fun editMode_communalAvailable() = - with(kosmos) { - testScope.runTest { - val available by collectLastValue(underTest.communalAvailable()) - setCommunalAvailable(false) - - assertThat(available).isFalse() - communalInteractor.setEditModeOpen(true) - assertThat(available).isTrue() - } + kosmos.runTest { + val available by collectLastValue(underTest.communalAvailable()) + setCommunalAvailable(false) + + assertThat(available).isFalse() + communalInteractor.setEditModeOpen(true) + assertThat(available).isTrue() } @Test @DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) fun gestureExclusionZone_setAfterInit() = - with(kosmos) { - testScope.runTest { - goToScene(CommunalScenes.Communal) - - assertThat(containerView.systemGestureExclusionRects) - .containsExactly( - Rect( - /* left= */ 0, - /* top= */ TOP_SWIPE_REGION_WIDTH, - /* right= */ CONTAINER_WIDTH, - /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH, - ) + kosmos.runTest { + goToScene(CommunalScenes.Communal) + + assertThat(containerView.systemGestureExclusionRects) + .containsExactly( + Rect( + /* left= */ 0, + /* top= */ TOP_SWIPE_REGION_WIDTH, + /* right= */ CONTAINER_WIDTH, + /* bottom= */ CONTAINER_HEIGHT - BOTTOM_SWIPE_REGION_WIDTH, ) - } + ) } @Test @EnableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) fun gestureExclusionZone_setAfterInit_fullSwipe() = - with(kosmos) { - testScope.runTest { - goToScene(CommunalScenes.Communal) + kosmos.runTest { + goToScene(CommunalScenes.Communal) - assertThat(containerView.systemGestureExclusionRects).isEmpty() - } + assertThat(containerView.systemGestureExclusionRects).isEmpty() } @Test @DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) fun gestureExclusionZone_unsetWhenShadeOpen() = - with(kosmos) { - testScope.runTest { - goToScene(CommunalScenes.Communal) + kosmos.runTest { + goToScene(CommunalScenes.Communal) - // Exclusion rect is set. - assertThat(containerView.systemGestureExclusionRects).isNotEmpty() + // Exclusion rect is set. + assertThat(containerView.systemGestureExclusionRects).isNotEmpty() - // Shade shows up. - shadeTestUtil.setQsExpansion(1.0f) - testableLooper.processAllMessages() + // Shade shows up. + shadeTestUtil.setQsExpansion(1.0f) + testableLooper.processAllMessages() - // Exclusion rects are unset. - assertThat(containerView.systemGestureExclusionRects).isEmpty() - } + // Exclusion rects are unset. + assertThat(containerView.systemGestureExclusionRects).isEmpty() } @Test @DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) fun gestureExclusionZone_unsetWhenBouncerOpen() = - with(kosmos) { - testScope.runTest { - goToScene(CommunalScenes.Communal) + kosmos.runTest { + goToScene(CommunalScenes.Communal) - // Exclusion rect is set. - assertThat(containerView.systemGestureExclusionRects).isNotEmpty() + // Exclusion rect is set. + assertThat(containerView.systemGestureExclusionRects).isNotEmpty() - // Bouncer is visible. - fakeKeyguardBouncerRepository.setPrimaryShow(true) - testableLooper.processAllMessages() + // Bouncer is visible. + fakeKeyguardBouncerRepository.setPrimaryShow(true) + testableLooper.processAllMessages() - // Exclusion rects are unset. - assertThat(containerView.systemGestureExclusionRects).isEmpty() - } + // Exclusion rects are unset. + assertThat(containerView.systemGestureExclusionRects).isEmpty() } @Test @DisableFlags(FLAG_HUBMODE_FULLSCREEN_VERTICAL_SWIPE_FIX) fun gestureExclusionZone_unsetWhenHubClosed() = - with(kosmos) { - testScope.runTest { - goToScene(CommunalScenes.Communal) + kosmos.runTest { + goToScene(CommunalScenes.Communal) - // Exclusion rect is set. - assertThat(containerView.systemGestureExclusionRects).isNotEmpty() + // Exclusion rect is set. + assertThat(containerView.systemGestureExclusionRects).isNotEmpty() - // Leave the hub. - goToScene(CommunalScenes.Blank) + // Leave the hub. + goToScene(CommunalScenes.Blank) - // Exclusion rect is unset. - assertThat(containerView.systemGestureExclusionRects).isEmpty() - } + // Exclusion rect is unset. + assertThat(containerView.systemGestureExclusionRects).isEmpty() } @Test fun fullScreenSwipeGesture_doNotProcessTouchesInNotificationStack() = - with(kosmos) { - testScope.runTest { - // Communal is closed. - goToScene(CommunalScenes.Blank) - whenever( - notificationStackScrollLayoutController.isBelowLastNotification( - any(), - any(), - ) - ) - .thenReturn(false) - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() - } + kosmos.runTest { + // Communal is closed. + goToScene(CommunalScenes.Blank) + whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any())) + .thenReturn(false) + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() } @Test fun fullScreenSwipeGesture_doNotProcessTouchesInUmo() = - with(kosmos) { - testScope.runTest { - // Communal is closed. - goToScene(CommunalScenes.Blank) - whenever(keyguardMediaController.isWithinMediaViewBounds(any(), any())) - .thenReturn(true) - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() - } + kosmos.runTest { + // Communal is closed. + goToScene(CommunalScenes.Blank) + whenever(keyguardMediaController.isWithinMediaViewBounds(any(), any())).thenReturn(true) + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() } @Test fun fullScreenSwipeGesture_doNotProcessTouchesInSmartspace() = - with(kosmos) { - testScope.runTest { - // Communal is closed. - goToScene(CommunalScenes.Blank) - whenever(lockscreenSmartspaceController.isWithinSmartspaceBounds(any(), any())) - .thenReturn(true) - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() - } + kosmos.runTest { + // Communal is closed. + goToScene(CommunalScenes.Blank) + whenever(lockscreenSmartspaceController.isWithinSmartspaceBounds(any(), any())) + .thenReturn(true) + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() } @Test fun onTouchEvent_hubOpen_touchesDispatched() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) - - // Touch event is sent to the container view. - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() - verify(containerView).onTouchEvent(DOWN_EVENT) - assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue() - verify(containerView).onTouchEvent(UP_EVENT) - } + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) + + // Touch event is sent to the container view. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() + verify(containerView).onTouchEvent(DOWN_EVENT) + assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue() + verify(containerView).onTouchEvent(UP_EVENT) } @Test fun onTouchEvent_editActivityShowing_touchesConsumedButNotDispatched() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) - - // Transitioning to or from edit mode. - communalInteractor.setEditActivityShowing(true) - testableLooper.processAllMessages() - - // onTouchEvent returns true to consume the touch, but it is not sent to the - // container view. - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() - verify(containerView, never()).onTouchEvent(any()) - } + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) + + // Transitioning to or from edit mode. + communalInteractor.setEditActivityShowing(true) + testableLooper.processAllMessages() + + // onTouchEvent returns true to consume the touch, but it is not sent to the + // container view. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() + verify(containerView, never()).onTouchEvent(any()) } @Test fun onTouchEvent_editModeTransitionStarted_touchesConsumedButNotDispatched() = - with(kosmos) { - testScope.runTest { - // Communal is open. - goToScene(CommunalScenes.Communal) - - // Leaving edit mode to return to the hub. - fakeKeyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.GLANCEABLE_HUB, - value = 1.0f, - transitionState = TransitionState.RUNNING, - ) + kosmos.runTest { + // Communal is open. + goToScene(CommunalScenes.Communal) + + // Leaving edit mode to return to the hub. + fakeKeyguardTransitionRepository.sendTransitionStep( + TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.GLANCEABLE_HUB, + value = 1.0f, + transitionState = TransitionState.RUNNING, ) - testableLooper.processAllMessages() + ) + testableLooper.processAllMessages() - // onTouchEvent returns true to consume the touch, but it is not sent to the - // container view. - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() - verify(containerView, never()).onTouchEvent(any()) - } + // onTouchEvent returns true to consume the touch, but it is not sent to the + // container view. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() + verify(containerView, never()).onTouchEvent(any()) } @Test fun onTouchEvent_shadeInteracting_movesNotDispatched() = - with(kosmos) { - testScope.runTest { - `whenever`(communalViewModel.swipeToHubEnabled()).thenReturn(true) - // On lockscreen. - goToScene(CommunalScenes.Blank) - whenever( - notificationStackScrollLayoutController.isBelowLastNotification( - any(), - any(), - ) - ) - .thenReturn(true) + kosmos.runTest { + swipeToHubEnabled.value = true - // Touches not consumed by default but are received by containerView. - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() - verify(containerView).onTouchEvent(DOWN_EVENT) + // On lockscreen. + goToScene(CommunalScenes.Blank) + whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any())) + .thenReturn(true) - // User is interacting with shade on lockscreen. - shadeTestUtil.setLockscreenShadeTracking(true) - testableLooper.processAllMessages() + // Touches not consumed by default but are received by containerView. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() + verify(containerView).onTouchEvent(DOWN_EVENT) - // A move event is ignored while the user is already interacting. - assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse() - verify(containerView, never()).onTouchEvent(MOVE_EVENT) + // User is interacting with shade on lockscreen. + shadeTestUtil.setLockscreenShadeTracking(true) + testableLooper.processAllMessages() - // An up event is still delivered. - assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse() - verify(containerView).onTouchEvent(UP_EVENT) - } + // A move event is ignored while the user is already interacting. + assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse() + verify(containerView, never()).onTouchEvent(MOVE_EVENT) + + // An up event is still delivered. + assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse() + verify(containerView).onTouchEvent(UP_EVENT) } @Test fun onTouchEvent_shadeExpanding_touchesNotDispatched() = - with(kosmos) { - testScope.runTest { - // On lockscreen. - goToScene(CommunalScenes.Blank) - whenever( - notificationStackScrollLayoutController.isBelowLastNotification( - any(), - any(), - ) - ) - .thenReturn(true) + kosmos.runTest { + // On lockscreen. + goToScene(CommunalScenes.Blank) + whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any())) + .thenReturn(true) - // Shade is open slightly. - shadeTestUtil.setShadeExpansion(0.01f) - testableLooper.processAllMessages() + // Shade is open slightly. + shadeTestUtil.setShadeExpansion(0.01f) + testableLooper.processAllMessages() - // Touches are not consumed. - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() - verify(containerView, never()).onTouchEvent(DOWN_EVENT) - } + // Touches are not consumed. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() + verify(containerView, never()).onTouchEvent(DOWN_EVENT) } @Test fun onTouchEvent_qsExpanding_touchesNotDispatched() = - with(kosmos) { - testScope.runTest { - // On lockscreen. - goToScene(CommunalScenes.Blank) - whenever( - notificationStackScrollLayoutController.isBelowLastNotification( - any(), - any(), - ) - ) - .thenReturn(true) + kosmos.runTest { + // On lockscreen. + goToScene(CommunalScenes.Blank) + whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any())) + .thenReturn(true) - // Shade is open slightly. - shadeTestUtil.setQsExpansion(0.01f) - testableLooper.processAllMessages() + // Shade is open slightly. + shadeTestUtil.setQsExpansion(0.01f) + testableLooper.processAllMessages() - // Touches are not consumed. - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() - verify(containerView, never()).onTouchEvent(DOWN_EVENT) - } + // Touches are not consumed. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() + verify(containerView, never()).onTouchEvent(DOWN_EVENT) } @Test fun onTouchEvent_bouncerInteracting_movesNotDispatched() = - with(kosmos) { - testScope.runTest { - `whenever`(communalViewModel.swipeToHubEnabled()).thenReturn(true) - // On lockscreen. - goToScene(CommunalScenes.Blank) - whenever( - notificationStackScrollLayoutController.isBelowLastNotification( - any(), - any(), - ) - ) - .thenReturn(true) + kosmos.runTest { + swipeToHubEnabled.value = true + // On lockscreen. + goToScene(CommunalScenes.Blank) + whenever(notificationStackScrollLayoutController.isBelowLastNotification(any(), any())) + .thenReturn(true) - // Touches not consumed by default but are received by containerView. - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() - verify(containerView).onTouchEvent(DOWN_EVENT) + // Touches not consumed by default but are received by containerView. + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() + verify(containerView).onTouchEvent(DOWN_EVENT) - // User is interacting with bouncer on lockscreen. - fakeKeyguardBouncerRepository.setPrimaryShow(true) - testableLooper.processAllMessages() + // User is interacting with bouncer on lockscreen. + fakeKeyguardBouncerRepository.setPrimaryShow(true) + testableLooper.processAllMessages() - // A move event is ignored while the user is already interacting. - assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse() - verify(containerView, never()).onTouchEvent(MOVE_EVENT) + // A move event is ignored while the user is already interacting. + assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse() + verify(containerView, never()).onTouchEvent(MOVE_EVENT) - // An up event is still delivered. - assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse() - verify(containerView).onTouchEvent(UP_EVENT) - } + // An up event is still delivered. + assertThat(underTest.onTouchEvent(UP_EVENT)).isFalse() + verify(containerView).onTouchEvent(UP_EVENT) } @EnableFlags(FLAG_GLANCEABLE_HUB_V2) @Test fun onTouchEvent_onLockscreenAndGlanceableHubV2_touchIgnored() = - with(kosmos) { - testScope.runTest { - kosmos.setCommunalV2ConfigEnabled(true) + kosmos.runTest { + swipeToHubEnabled.value = false + setCommunalV2ConfigEnabled(true) - // On lockscreen. - goToScene(CommunalScenes.Blank) + // On lockscreen. + goToScene(CommunalScenes.Blank) - assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() - verify(containerView, never()).onTouchEvent(DOWN_EVENT) - } + assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() + verify(containerView, never()).onTouchEvent(DOWN_EVENT) } @Test - fun disposeView_destroysTouchMonitor() { - clearInvocations(touchMonitor) + fun disposeView_destroysTouchMonitor() = + kosmos.runTest { + clearInvocations(touchMonitor) - underTest.disposeView() + underTest.disposeView() - verify(touchMonitor).destroy() - } + verify(touchMonitor).destroy() + } - private fun initAndAttachContainerView() { + private fun Kosmos.initAndAttachContainerView() { val mockInsets = mock<WindowInsets> { on { getInsets(WindowInsets.Type.systemGestures()) } doReturn FAKE_INSETS @@ -802,8 +707,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { testableLooper.processAllMessages() } - private suspend fun goToScene(scene: SceneKey) { - communalRepository.changeScene(scene) + private suspend fun Kosmos.goToScene(scene: SceneKey) { + fakeCommunalSceneRepository.changeScene(scene) if (scene == CommunalScenes.Communal) { kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt index fcbf0fe9a37a..510d6fe2b776 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt @@ -17,19 +17,23 @@ package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel import android.platform.test.annotations.EnableFlags +import androidx.compose.runtime.snapshots.Snapshot import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.runTest import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.lifecycle.activateIn import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel -import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips +import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -37,22 +41,41 @@ import org.junit.runner.RunWith @EnableFlags(StatusBarPopupChips.FLAG_NAME) @RunWith(AndroidJUnit4::class) class StatusBarPopupChipsViewModelTest : SysuiTestCase() { - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - private val mediaFilterRepository = kosmos.mediaFilterRepository - private val underTest = kosmos.statusBarPopupChipsViewModel + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val underTest = kosmos.statusBarPopupChipsViewModelFactory.create() + + @Before + fun setUp() { + underTest.activateIn(kosmos.testScope) + } @Test fun shownPopupChips_allHidden_empty() = - testScope.runTest { - val shownPopupChips by collectLastValue(underTest.shownPopupChips) + kosmos.runTest { + val shownPopupChips = underTest.shownPopupChips assertThat(shownPopupChips).isEmpty() } @Test fun shownPopupChips_activeMedia_restHidden_mediaControlChipShown() = - testScope.runTest { - val shownPopupChips by collectLastValue(underTest.shownPopupChips) + kosmos.runTest { + val shownPopupChips = underTest.shownPopupChips + val userMedia = MediaData(active = true, song = "test") + val instanceId = userMedia.instanceId + + mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) + + Snapshot.takeSnapshot { + assertThat(shownPopupChips).hasSize(1) + assertThat(shownPopupChips.first().chipId).isEqualTo(PopupChipId.MediaControl) + } + } + + @Test + fun shownPopupChips_mediaChipToggled_popupShown() = + kosmos.runTest { + val shownPopupChips = underTest.shownPopupChips val userMedia = MediaData(active = true, song = "test") val instanceId = userMedia.instanceId @@ -60,7 +83,13 @@ class StatusBarPopupChipsViewModelTest : SysuiTestCase() { mediaFilterRepository.addSelectedUserMediaEntry(userMedia) mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) - assertThat(shownPopupChips).hasSize(1) - assertThat(shownPopupChips!!.first().chipId).isEqualTo(PopupChipId.MediaControl) + Snapshot.takeSnapshot { + assertThat(shownPopupChips).hasSize(1) + val mediaChip = shownPopupChips.first() + assertThat(mediaChip.isPopupShown).isFalse() + + mediaChip.showPopup.invoke() + assertThat(shownPopupChips.first().isPopupShown).isTrue() + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java index 4ff09d3bc6af..e8b50d580c33 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java @@ -45,6 +45,9 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import android.os.SystemClock; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArrayMap; @@ -74,10 +77,14 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable; import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.notification.row.NotificationTestHelper; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.util.time.FakeSystemClock; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -127,6 +134,9 @@ public class ShadeListBuilderTest extends SysuiTestCase { private TestableStabilityManager mStabilityManager; private TestableNotifFilter mFinalizeFilter; + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private Map<String, Integer> mNextIdMap = new ArrayMap<>(); private int mNextRank = 0; @@ -561,6 +571,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) public void testFilter_resetsInitalizationTime() { // GIVEN a NotifFilter that filters out a specific package NotifFilter filter1 = spy(new PackageFilter(PACKAGE_1)); @@ -584,6 +595,31 @@ public class ShadeListBuilderTest extends SysuiTestCase { } @Test + @EnableFlags(NotificationBundleUi.FLAG_NAME) + public void testFilter_resetsInitializationTime_onRow() throws Exception { + // GIVEN a NotifFilter that filters out a specific package + NotifFilter filter1 = spy(new PackageFilter(PACKAGE_1)); + mListBuilder.addFinalizeFilter(filter1); + + // GIVEN a notification that was initialized 1 second ago that will be filtered out + final NotificationEntry entry = new NotificationEntryBuilder() + .setPkg(PACKAGE_1) + .setId(nextId(PACKAGE_1)) + .setRank(nextRank()) + .build(); + entry.setRow(new NotificationTestHelper(mContext, mDependency).createRow()); + entry.getRow().setInitializationTime(SystemClock.elapsedRealtime() - 1000); + assertTrue(entry.getRow().hasFinishedInitialization()); + + // WHEN the pipeline is kicked off + mReadyForBuildListener.onBuildList(singletonList(entry), "test"); + mPipelineChoreographer.runIfScheduled(); + + // THEN the entry's initialization time is reset + assertFalse(entry.getRow().hasFinishedInitialization()); + } + + @Test public void testNotifFiltersCanBePreempted() { // GIVEN two notif filters NotifFilter filter1 = spy(new PackageFilter(PACKAGE_2)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index 77b116e2e465..24d8d1cc8fae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.row; +import static android.app.Flags.FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES; + import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL; import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.PKG; import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.USER_HANDLE; @@ -29,6 +31,7 @@ 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.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -72,6 +75,7 @@ import com.android.systemui.statusbar.notification.headsup.PinnedStatus; import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded; import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi; import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization; import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; @@ -189,6 +193,54 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES) + public void setSensitive_doesNothingIfCalledAgain() throws Exception { + ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + measureAndLayout(row); + + // GIVEN a mocked public layout + NotificationContentView mockPublicLayout = mock(NotificationContentView.class); + row.setPublicLayout(mockPublicLayout); + + // GIVEN a sensitive notification row that's currently redacted + row.setHideSensitiveForIntrinsicHeight(true); + row.setSensitive(true, true); + assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPublicLayout()); + verify(mockPublicLayout).requestSelectLayout(eq(true)); + clearInvocations(mockPublicLayout); + + // WHEN the row is set to the same sensitive settings + row.setSensitive(true, true); + + // VERIFY that the layout is not updated again + assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPublicLayout()); + verify(mockPublicLayout, never()).requestSelectLayout(anyBoolean()); + } + + @Test + @EnableFlags(FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES) + public void testSetSensitiveOnNotifRowUpdatesLayout() throws Exception { + // GIVEN a sensitive notification row that's currently redacted + ExpandableNotificationRow row = mNotificationTestHelper.createRow(); + measureAndLayout(row); + row.setHideSensitiveForIntrinsicHeight(true); + row.setSensitive(true, true); + assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPublicLayout()); + + // GIVEN a mocked private layout + NotificationContentView mockPrivateLayout = mock(NotificationContentView.class); + row.setPrivateLayout(mockPrivateLayout); + + // WHEN the row is set to no longer be sensitive + row.setSensitive(false, true); + + // VERIFY that the layout is updated + assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPrivateLayout()); + verify(mockPrivateLayout).requestSelectLayout(eq(true)); + } + + @Test + @DisableFlags(FLAG_NOTIFICATIONS_REDESIGN_TEMPLATES) public void testSetSensitiveOnNotifRowNotifiesOfHeightChange() throws Exception { // GIVEN a sensitive notification row that's currently redacted ExpandableNotificationRow row = mNotificationTestHelper.createRow(); @@ -538,6 +590,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { } @Test + @DisableFlags(NotificationBundleUi.FLAG_NAME) public void testGetIsNonblockable() throws Exception { ExpandableNotificationRow row = mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification()); @@ -612,8 +665,8 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { Assert.assertTrue(group.getAttachedChildren().isEmpty()); Assert.assertNotEquals(group, child.getNotificationParent()); verify(mNotificationTestHelper.getMockLogger()).logSkipAttachingKeepInParentChild( - /*child=*/ child.getEntry(), - /*newParent=*/ group.getEntry() + /*child=*/ child.getLoggingKey(), + /*newParent=*/ group.getLoggingKey() ); } @@ -629,7 +682,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { Assert.assertNull(child.getNotificationParent()); Assert.assertFalse(child.keepInParentForDismissAnimation()); verify(mNotificationTestHelper.getMockLogger()) - .logCancelAppearDrawing(child.getEntry(), false); + .logCancelAppearDrawing(child.getLoggingKey(), false); verifyNoMoreInteractions(mNotificationTestHelper.getMockLogger()); } @@ -645,8 +698,8 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { Assert.assertNull(child.getNotificationParent()); Assert.assertFalse(child.keepInParentForDismissAnimation()); verify(mNotificationTestHelper.getMockLogger()).logKeepInParentChildDetached( - /*child=*/ child.getEntry(), - /*oldParent=*/ group.getEntry() + /*child=*/ child.getLoggingKey(), + /*oldParent=*/ group.getLoggingKey() ); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt index 699e8c30afde..c874bc6056c6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt @@ -23,6 +23,7 @@ import android.service.notification.StatusBarNotification import android.testing.TestableLooper import android.testing.ViewUtils import android.view.NotificationHeaderView +import android.view.NotificationTopLineView import android.view.View import android.view.ViewGroup import android.widget.FrameLayout @@ -35,8 +36,10 @@ import com.android.internal.widget.NotificationActionListLayout import com.android.internal.widget.NotificationExpandButton import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.notification.FeedbackIcon +import com.android.systemui.statusbar.notification.collection.EntryAdapter import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier +import com.android.systemui.statusbar.notification.shared.NotificationBundleUi import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever @@ -80,10 +83,25 @@ class NotificationContentViewTest : SysuiTestCase() { fakeParent = spy(FrameLayout(mContext, /* attrs= */ null).also { it.visibility = View.GONE }) val mockEntry = createMockNotificationEntry() + val mockEntryAdapter = createMockNotificationEntryAdapter() row = spy( - ExpandableNotificationRow(mContext, /* attrs= */ null, mockEntry).apply { - entry = mockEntry + when (NotificationBundleUi.isEnabled) { + true -> { + ExpandableNotificationRow( + mContext, + /* attrs= */ null, + UserHandle.CURRENT + ).apply { + entry = mockEntry + entryAdapter = mockEntryAdapter + } + } + false -> { + ExpandableNotificationRow(mContext, /* attrs= */ null, mockEntry).apply { + entry = mockEntry + } + } } ) ViewUtils.attachView(fakeParent) @@ -270,7 +288,7 @@ class NotificationContentViewTest : SysuiTestCase() { val icon = FeedbackIcon( R.drawable.ic_feedback_alerted, - R.string.notification_feedback_indicator_alerted + R.string.notification_feedback_indicator_alerted, ) view.setFeedbackIcon(icon) @@ -291,10 +309,7 @@ class NotificationContentViewTest : SysuiTestCase() { val mockHeadsUpEB = mock<NotificationExpandButton>() val mockHeadsUp = createMockNotificationHeaderView(contractedHeight, mockHeadsUpEB) - val view = - createContentView( - isSystemExpanded = false, - ) + val view = createContentView(isSystemExpanded = false) // Update all 3 child forms view.apply { @@ -319,12 +334,14 @@ class NotificationContentViewTest : SysuiTestCase() { private fun createMockNotificationHeaderView( height: Int, - mockExpandedEB: NotificationExpandButton + mockExpandedEB: NotificationExpandButton, ) = spy(NotificationHeaderView(mContext, /* attrs= */ null).apply { minimumHeight = height }) .apply { whenever(this.animate()).thenReturn(mock()) whenever(this.findViewById<View>(R.id.expand_button)).thenReturn(mockExpandedEB) + whenever(this.findViewById<View>(R.id.notification_top_line)) + .thenReturn(mock<NotificationTopLineView>()) } @Test @@ -344,7 +361,7 @@ class NotificationContentViewTest : SysuiTestCase() { isSystemExpanded = false, contractedView = mockContracted, expandedView = mockExpanded, - headsUpView = mockHeadsUp + headsUpView = mockHeadsUp, ) view.setRemoteInputVisible(true) @@ -373,7 +390,7 @@ class NotificationContentViewTest : SysuiTestCase() { isSystemExpanded = false, contractedView = mockContracted, expandedView = mockExpanded, - headsUpView = mockHeadsUp + headsUpView = mockHeadsUp, ) view.setRemoteInputVisible(false) @@ -597,6 +614,7 @@ class NotificationContentViewTest : SysuiTestCase() { whenever(this.entry).thenReturn(notificationEntry) whenever(this.context).thenReturn(mContext) whenever(this.bubbleClickListener).thenReturn(View.OnClickListener {}) + whenever(this.entryAdapter).thenReturn(createMockNotificationEntryAdapter()) } private fun createMockNotificationEntry() = @@ -610,6 +628,9 @@ class NotificationContentViewTest : SysuiTestCase() { whenever(sbnMock.user).thenReturn(userMock) } + private fun createMockNotificationEntryAdapter() = + mock<EntryAdapter>() + private fun createLinearLayoutWithBottomMargin(bottomMargin: Int): LinearLayout { val outerLayout = LinearLayout(mContext) val innerLayout = LinearLayout(mContext) @@ -635,7 +656,7 @@ class NotificationContentViewTest : SysuiTestCase() { contractedView: View = createViewWithHeight(contractedHeight), expandedView: View = createViewWithHeight(expandedHeight), headsUpView: View = createViewWithHeight(contractedHeight), - row: ExpandableNotificationRow = this.row + row: ExpandableNotificationRow = this.row, ): NotificationContentView { val height = if (isSystemExpanded) expandedHeight else contractedHeight doReturn(height).whenever(row).intrinsicHeight @@ -647,7 +668,7 @@ class NotificationContentViewTest : SysuiTestCase() { setHeights( /* smallHeight= */ contractedHeight, /* headsUpMaxHeight= */ contractedHeight, - /* maxHeight= */ expandedHeight + /* maxHeight= */ expandedHeight, ) contractedChild = contractedView expandedChild = expandedView diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt index 3d4c90140adb..99b99ee1860b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerWithScenesTest.kt @@ -427,7 +427,6 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() { .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE) .setImportance(NotificationManager.IMPORTANCE_HIGH) .build() - whenever(row.getIsNonblockable()).thenReturn(false) whenever(highPriorityProvider.isHighPriority(entry)).thenReturn(true) val statusBarNotification = entry.sbn gutsManager.initializeNotificationInfo(row, notificationInfoView) @@ -463,7 +462,6 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() { NotificationEntryHelper.modifyRanking(row.entry) .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE) .build() - whenever(row.getIsNonblockable()).thenReturn(false) val statusBarNotification = row.entry.sbn val entry = row.entry gutsManager.initializeNotificationInfo(row, notificationInfoView) @@ -499,7 +497,6 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() { NotificationEntryHelper.modifyRanking(row.entry) .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE) .build() - whenever(row.getIsNonblockable()).thenReturn(false) val statusBarNotification = row.entry.sbn val entry = row.entry gutsManager.initializeNotificationInfo(row, notificationInfoView) @@ -566,7 +563,7 @@ class NotificationGutsManagerWithScenesTest : SysuiTestCase() { ): NotificationMenuRowPlugin.MenuItem { val menuRow: NotificationMenuRowPlugin = NotificationMenuRow(mContext, peopleNotificationIdentifier) - menuRow.createMenu(row, row!!.entry.sbn) + menuRow.createMenu(row) val menuItem = menuRow.getLongpressMenuItem(mContext) Assert.assertNotNull(menuItem) return menuItem 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 6ac20d40f2dc..955de273c426 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 @@ -675,7 +675,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testClearNotifications_clearAllInProgress() { ExpandableNotificationRow row = createClearableRow(); - when(row.getEntry().hasFinishedInitialization()).thenReturn(true); + when(row.hasFinishedInitialization()).thenReturn(true); doReturn(true).when(mStackScroller).isVisible(row); mStackScroller.addContainerView(row); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 14a1233045bb..10886760b521 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -63,6 +63,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.ShadeInterpolation; import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants; import com.android.systemui.dock.DockManager; +import com.android.systemui.flags.DisableSceneContainer; import com.android.systemui.flags.EnableSceneContainer; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository; @@ -118,10 +119,8 @@ public class ScrimControllerTest extends SysuiTestCase { @Rule public Expect mExpect = Expect.create(); private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this); - private final FakeConfigurationController mConfigurationController = - new FakeConfigurationController(); - private final LargeScreenShadeInterpolator - mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator(); + private FakeConfigurationController mConfigurationController; + private LargeScreenShadeInterpolator mLinearLargeScreenShadeInterpolator; private final TestScope mTestScope = mKosmos.getTestScope(); private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope()); @@ -137,6 +136,7 @@ public class ScrimControllerTest extends SysuiTestCase { private boolean mAlwaysOnEnabled; private TestableLooper mLooper; private Context mContext; + @Mock private DozeParameters mDozeParameters; @Mock private LightBarController mLightBarController; @Mock private DelayedWakeLock.Factory mDelayedWakeLockFactory; @@ -149,12 +149,11 @@ public class ScrimControllerTest extends SysuiTestCase { @Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel; @Mock private AlternateBouncerToGoneTransitionViewModel mAlternateBouncerToGoneTransitionViewModel; - private final KeyguardTransitionInteractor mKeyguardTransitionInteractor = - mKosmos.getKeyguardTransitionInteractor(); - private final FakeKeyguardTransitionRepository mKeyguardTransitionRepository = - mKosmos.getKeyguardTransitionRepository(); @Mock private KeyguardInteractor mKeyguardInteractor; + private KeyguardTransitionInteractor mKeyguardTransitionInteractor; + private FakeKeyguardTransitionRepository mKeyguardTransitionRepository; + // TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The // event-dispatch-on-registration pattern caused some of these unit tests to fail.) @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @@ -238,6 +237,9 @@ public class ScrimControllerTest extends SysuiTestCase { when(mContext.getColor(com.android.internal.R.color.materialColorSurface)) .thenAnswer(invocation -> mSurfaceColor); + mConfigurationController = new FakeConfigurationController(); + mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator(); + mScrimBehind = spy(new ScrimView(mContext)); mScrimInFront = new ScrimView(mContext); mNotificationsScrim = new ScrimView(mContext); @@ -270,6 +272,9 @@ public class ScrimControllerTest extends SysuiTestCase { when(mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha()) .thenReturn(emptyFlow()); + mKeyguardTransitionRepository = mKosmos.getKeyguardTransitionRepository(); + mKeyguardTransitionInteractor = mKosmos.getKeyguardTransitionInteractor(); + mScrimController = new ScrimController( mLightBarController, mDozeParameters, @@ -322,6 +327,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToKeyguard() { mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); finishAnimationsImmediately(); @@ -337,6 +343,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToShadeLocked() { mScrimController.legacyTransitionTo(SHADE_LOCKED); mScrimController.setQsPosition(1f, 0); @@ -373,6 +380,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToShadeLocked_clippingQs() { mScrimController.setClipsQsScrim(true); mScrimController.legacyTransitionTo(SHADE_LOCKED); @@ -391,6 +399,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToOff() { mScrimController.legacyTransitionTo(ScrimState.OFF); finishAnimationsImmediately(); @@ -406,6 +415,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToAod_withRegularWallpaper() { mScrimController.legacyTransitionTo(ScrimState.AOD); finishAnimationsImmediately(); @@ -421,6 +431,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToAod_withFrontAlphaUpdates() { // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state. mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); @@ -465,6 +476,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToAod_afterDocked_ignoresAlwaysOnAndUpdatesFrontAlpha() { // Assert that setting the AOD front scrim alpha doesn't take effect in a non-AOD state. mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); @@ -506,6 +518,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToPulsing_withFrontAlphaUpdates() { // Pre-condition // Need to go to AoD first because PULSING doesn't change @@ -551,6 +564,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToKeyguardBouncer() { mScrimController.legacyTransitionTo(BOUNCER); finishAnimationsImmediately(); @@ -571,6 +585,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void lockscreenToHubTransition_setsBehindScrimAlpha() { // Start on lockscreen. mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); @@ -617,6 +632,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void hubToLockscreenTransition_setsViewAlpha() { // Start on glanceable hub. mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB); @@ -663,6 +679,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToHub() { mScrimController.setRawPanelExpansionFraction(0f); mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN); @@ -677,6 +694,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void openBouncerOnHub() { mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB); @@ -706,6 +724,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void openShadeOnHub() { mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB); @@ -734,6 +753,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToHubOverDream() { mScrimController.setRawPanelExpansionFraction(0f); mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN); @@ -748,6 +768,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void openBouncerOnHubOverDream() { mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM); @@ -777,6 +798,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void openShadeOnHubOverDream() { mScrimController.legacyTransitionTo(ScrimState.GLANCEABLE_HUB_OVER_DREAM); @@ -805,6 +827,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() { assertEquals(BOUNCER.getBehindTint(), 0x112233); mSurfaceColor = 0x223344; @@ -813,6 +836,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void onThemeChangeWhileClipQsScrim_bouncerBehindTint_remainsBlack() { mScrimController.setClipsQsScrim(true); mScrimController.legacyTransitionTo(BOUNCER); @@ -825,6 +849,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToKeyguardBouncer_clippingQs() { mScrimController.setClipsQsScrim(true); mScrimController.legacyTransitionTo(BOUNCER); @@ -845,6 +870,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void disableClipQsScrimWithoutStateTransition_updatesTintAndAlpha() { mScrimController.setClipsQsScrim(true); mScrimController.legacyTransitionTo(BOUNCER); @@ -867,6 +893,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void enableClipQsScrimWithoutStateTransition_updatesTintAndAlpha() { mScrimController.setClipsQsScrim(false); mScrimController.legacyTransitionTo(BOUNCER); @@ -889,6 +916,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToBouncer() { mScrimController.legacyTransitionTo(ScrimState.BOUNCER_SCRIMMED); finishAnimationsImmediately(); @@ -902,6 +930,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToUnlocked_clippedQs() { mScrimController.setClipsQsScrim(true); mScrimController.setRawPanelExpansionFraction(0f); @@ -960,6 +989,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToUnlocked_nonClippedQs_followsLargeScreensInterpolator() { mScrimController.setClipsQsScrim(false); mScrimController.setRawPanelExpansionFraction(0f); @@ -999,6 +1029,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void scrimStateCallback() { mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); finishAnimationsImmediately(); @@ -1014,6 +1045,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void panelExpansion() { mScrimController.setRawPanelExpansionFraction(0f); mScrimController.setRawPanelExpansionFraction(0.5f); @@ -1036,6 +1068,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void qsExpansion() { reset(mScrimBehind); mScrimController.setQsPosition(1f, 999 /* value doesn't matter */); @@ -1048,6 +1081,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void qsExpansion_clippingQs() { reset(mScrimBehind); mScrimController.setClipsQsScrim(true); @@ -1061,6 +1095,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void qsExpansion_half_clippingQs() { reset(mScrimBehind); mScrimController.setClipsQsScrim(true); @@ -1074,6 +1109,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void panelExpansionAffectsAlpha() { mScrimController.setRawPanelExpansionFraction(0f); mScrimController.setRawPanelExpansionFraction(0.5f); @@ -1096,6 +1132,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToUnlockedFromOff() { // Simulate unlock with fingerprint without AOD mScrimController.legacyTransitionTo(ScrimState.OFF); @@ -1118,6 +1155,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToUnlockedFromAod() { // Simulate unlock with fingerprint mScrimController.legacyTransitionTo(ScrimState.AOD); @@ -1140,6 +1178,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void scrimBlanksBeforeLeavingAod() { // Simulate unlock with fingerprint mScrimController.legacyTransitionTo(ScrimState.AOD); @@ -1163,6 +1202,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void scrimBlankCallbackWhenUnlockingFromPulse() { boolean[] blanked = {false}; // Simulate unlock with fingerprint @@ -1181,6 +1221,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void blankingNotRequired_leavingAoD() { // GIVEN display does NOT need blanking when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(false); @@ -1236,6 +1277,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testScrimCallback() { int[] callOrder = {0, 0, 0}; int[] currentCall = {0}; @@ -1262,12 +1304,14 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testScrimCallbacksWithoutAmbientDisplay() { mAlwaysOnEnabled = false; testScrimCallback(); } @Test + @DisableSceneContainer public void testScrimCallbackCancelled() { boolean[] cancelledCalled = {false}; mScrimController.legacyTransitionTo(ScrimState.AOD, new ScrimController.Callback() { @@ -1281,6 +1325,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testHoldsWakeLock_whenAOD() { mScrimController.legacyTransitionTo(ScrimState.AOD); verify(mWakeLock).acquire(anyString()); @@ -1290,6 +1335,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testDoesNotHoldWakeLock_whenUnlocking() { mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); finishAnimationsImmediately(); @@ -1297,6 +1343,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testCallbackInvokedOnSameStateTransition() { mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); finishAnimationsImmediately(); @@ -1306,6 +1353,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testConservesExpansionOpacityAfterTransition() { mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); mScrimController.setRawPanelExpansionFraction(0.5f); @@ -1323,6 +1371,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testCancelsOldAnimationBeforeBlanking() { mScrimController.legacyTransitionTo(ScrimState.AOD); finishAnimationsImmediately(); @@ -1335,6 +1384,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testScrimsAreNotFocusable() { assertFalse("Behind scrim should not be focusable", mScrimBehind.isFocusable()); assertFalse("Front scrim should not be focusable", mScrimInFront.isFocusable()); @@ -1343,6 +1393,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testEatsTouchEvent() { HashSet<ScrimState> eatsTouches = new HashSet<>(Collections.singletonList(ScrimState.AOD)); @@ -1359,6 +1410,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testAnimatesTransitionToAod() { when(mDozeParameters.shouldControlScreenOff()).thenReturn(false); ScrimState.AOD.prepare(ScrimState.KEYGUARD); @@ -1373,6 +1425,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testIsLowPowerMode() { HashSet<ScrimState> lowPowerModeStates = new HashSet<>(Arrays.asList( ScrimState.OFF, ScrimState.AOD, ScrimState.PULSING)); @@ -1390,6 +1443,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testScrimsOpaque_whenShadeFullyExpanded() { mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); mScrimController.setRawPanelExpansionFraction(1); @@ -1404,6 +1458,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testScrimsVisible_whenShadeVisible() { mScrimController.setClipsQsScrim(true); mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); @@ -1419,6 +1474,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testDoesntAnimate_whenUnlocking() { // LightRevealScrim will animate the transition, we should only hide the keyguard scrims. ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD); @@ -1439,6 +1495,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testScrimsVisible_whenShadeVisible_clippingQs() { mScrimController.setClipsQsScrim(true); mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); @@ -1454,6 +1511,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testScrimsVisible_whenShadeVisibleOnLockscreen() { mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); mScrimController.setQsPosition(0.25f, 300); @@ -1465,6 +1523,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testNotificationScrimTransparent_whenOnLockscreen() { mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); // even if shade is not pulled down, panel has expansion of 1 on the lockscreen @@ -1477,6 +1536,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testNotificationScrimVisible_afterOpeningShadeFromLockscreen() { mScrimController.setRawPanelExpansionFraction(1); mScrimController.legacyTransitionTo(SHADE_LOCKED); @@ -1488,6 +1548,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void qsExpansion_BehindTint_shadeLocked_bouncerActive_usesBouncerProgress() { when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true); // clipping doesn't change tested logic but allows to assert scrims more in line with @@ -1504,6 +1565,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void expansionNotificationAlpha_shadeLocked_bouncerActive_usesBouncerInterpolator() { when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true); @@ -1520,6 +1582,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void expansionNotificationAlpha_shadeLocked_bouncerNotActive_usesShadeInterpolator() { when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false); @@ -1535,6 +1598,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void notificationAlpha_unnocclusionAnimating_bouncerNotActive_usesKeyguardNotifAlpha() { when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false); @@ -1554,6 +1618,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void notificationAlpha_inKeyguardState_bouncerActive_usesInvertedBouncerInterpolator() { when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(true); mScrimController.setClipsQsScrim(true); @@ -1574,6 +1639,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void notificationAlpha_inKeyguardState_bouncerNotActive_usesInvertedShadeInterpolator() { when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false); mScrimController.setClipsQsScrim(true); @@ -1594,6 +1660,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void behindTint_inKeyguardState_bouncerNotActive_usesKeyguardBehindTint() { when(mStatusBarKeyguardViewManager.isPrimaryBouncerInTransit()).thenReturn(false); mScrimController.setClipsQsScrim(false); @@ -1605,6 +1672,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testNotificationTransparency_followsTransitionToFullShade() { mScrimController.setClipsQsScrim(true); @@ -1646,6 +1714,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void notificationTransparency_followsNotificationScrimProgress() { mScrimController.legacyTransitionTo(SHADE_LOCKED); mScrimController.setRawPanelExpansionFraction(1.0f); @@ -1662,6 +1731,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void notificationAlpha_qsNotClipped_alphaMatchesNotificationExpansionProgress() { mScrimController.setClipsQsScrim(false); mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); @@ -1697,6 +1767,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void setNotificationsOverScrollAmount_setsTranslationYOnNotificationsScrim() { int overScrollAmount = 10; @@ -1706,6 +1777,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void setNotificationsOverScrollAmount_doesNotSetTranslationYOnBehindScrim() { int overScrollAmount = 10; @@ -1715,6 +1787,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void setNotificationsOverScrollAmount_doesNotSetTranslationYOnFrontScrim() { int overScrollAmount = 10; @@ -1724,6 +1797,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void notificationBoundsTopGetsPassedToKeyguard() { mScrimController.legacyTransitionTo(SHADE_LOCKED); mScrimController.setQsPosition(1f, 0); @@ -1734,6 +1808,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void notificationBoundsTopDoesNotGetPassedToKeyguardWhenNotifScrimIsNotVisible() { mScrimController.setKeyguardOccluded(true); mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); @@ -1744,6 +1819,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void transitionToDreaming() { mScrimController.setRawPanelExpansionFraction(0f); mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN); @@ -1763,6 +1839,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void keyguardGoingAwayUpdateScrims() { when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(true); mScrimController.updateScrims(); @@ -1772,6 +1849,7 @@ public class ScrimControllerTest extends SysuiTestCase { @Test + @DisableSceneContainer public void setUnOccludingAnimationKeyguard() { mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); finishAnimationsImmediately(); @@ -1786,6 +1864,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testHidesScrimFlickerInActivity() { mScrimController.setKeyguardOccluded(true); mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); @@ -1804,6 +1883,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void notificationAlpha_inKeyguardState_bouncerNotActive_clipsQsScrimFalse() { mScrimController.setClipsQsScrim(false); mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); @@ -1813,6 +1893,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void aodStateSetsFrontScrimToNotBlend() { mScrimController.legacyTransitionTo(ScrimState.AOD); assertFalse("Front scrim should not blend with main color", @@ -1820,6 +1901,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void applyState_unlocked_bouncerShowing() { mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); mScrimController.setBouncerHiddenFraction(0.99f); @@ -1829,6 +1911,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void ignoreTransitionRequestWhileKeyguardTransitionRunning() { mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); mScrimController.mBouncerToGoneTransition.accept( @@ -1841,6 +1924,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void primaryBouncerToGoneOnFinishCallsKeyguardFadedAway() { when(mKeyguardStateController.isKeyguardFadingAway()).thenReturn(true); mScrimController.mBouncerToGoneTransition.accept( @@ -1851,6 +1935,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void primaryBouncerToGoneOnFinishCallsLightBarController() { reset(mLightBarController); mScrimController.mBouncerToGoneTransition.accept( @@ -1862,6 +1947,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testDoNotAnimateChangeIfOccludeAnimationPlaying() { mScrimController.setOccludeAnimationPlaying(true); mScrimController.legacyTransitionTo(ScrimState.UNLOCKED); @@ -1870,6 +1956,7 @@ public class ScrimControllerTest extends SysuiTestCase { } @Test + @DisableSceneContainer public void testNotifScrimAlpha_1f_afterUnlockFinishedAndExpanded() { mScrimController.legacyTransitionTo(ScrimState.KEYGUARD); when(mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(true); @@ -1942,9 +2029,9 @@ public class ScrimControllerTest extends SysuiTestCase { // Check combined scrim visibility. final int visibility; - if (scrimToAlpha.values().contains(OPAQUE)) { + if (scrimToAlpha.containsValue(OPAQUE)) { visibility = OPAQUE; - } else if (scrimToAlpha.values().contains(SEMI_TRANSPARENT)) { + } else if (scrimToAlpha.containsValue(SEMI_TRANSPARENT)) { visibility = SEMI_TRANSPARENT; } else { visibility = TRANSPARENT; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 3190d3ae8f16..28eafa937097 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -76,6 +76,7 @@ import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.ShadeControllerImpl; import com.android.systemui.shade.data.repository.FakeShadeRepository; import com.android.systemui.shade.data.repository.ShadeAnimationRepository; +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl; import com.android.systemui.statusbar.CommandQueue; @@ -171,6 +172,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { private final FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private ExpandableNotificationRow mNotificationRow; private ExpandableNotificationRow mBubbleNotificationRow; + private FakeShadeDialogContextInteractor mContextInteractor; private final Answer<Void> mCallOnDismiss = answerVoid( (OnDismissAction dismissAction, Runnable cancel, @@ -187,6 +189,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mDependency, TestableLooper.get(this)); + mContextInteractor = new FakeShadeDialogContextInteractor(mContext); + // Create standard notification with contentIntent mNotificationRow = notificationTestHelper.createRow(); StatusBarNotification sbn = mNotificationRow.getEntry().getSbn(); @@ -199,10 +203,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { bubbleSbn.getNotification().contentIntent = mContentIntent; bubbleSbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; -// ArrayList<NotificationEntry> activeNotifications = new ArrayList<>(); -// activeNotifications.add(mNotificationRow.getEntry()); -// activeNotifications.add(mBubbleNotificationRow.getEntry()); -// when(mEntryManager.getVisibleNotifications()).thenReturn(activeNotifications); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); when(mOnUserInteractionCallback.registerFutureDismissal(eq(mNotificationRow.getEntry()), anyInt())).thenReturn(mFutureDismissalRunnable); @@ -232,6 +232,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter = new StatusBarNotificationActivityStarter( getContext(), + mContextInteractor, mHandler, mUiBgExecutor, mVisibilityProvider, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt index df5c6e916931..a51e919636ee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt @@ -129,11 +129,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { @Mock private lateinit var context: Context private val mobileMappings = FakeMobileMappingsProxy() - private val systemUiCarrierConfig = - SystemUiCarrierConfig( - SUB_1_ID, - createTestConfig(), - ) + private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, createTestConfig()) private val testDispatcher = UnconfinedTestDispatcher() private val testScope = TestScope(testDispatcher) @@ -902,11 +898,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN")) - val intentWithoutInfo = - spnIntent( - showSpn = false, - showPlmn = false, - ) + val intentWithoutInfo = spnIntent(showSpn = false, showPlmn = false) captor.lastValue.onReceive(context, intentWithoutInfo) @@ -929,11 +921,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN")) - val intentWithoutInfo = - spnIntent( - showSpn = false, - showPlmn = false, - ) + val intentWithoutInfo = spnIntent(showSpn = false, showPlmn = false) captor.lastValue.onReceive(context, intentWithoutInfo) @@ -1301,7 +1289,6 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { } @Test - @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) fun isNonTerrestrial_updatesFromCallback0() = testScope.runTest { val latest by collectLastValue(underTest.isNonTerrestrial) @@ -1430,10 +1417,7 @@ class MobileConnectionRepositoryTest : SysuiTestCase() { return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager) } - private fun carrierIdIntent( - subId: Int = SUB_1_ID, - carrierId: Int, - ): Intent = + private fun carrierIdIntent(subId: Int = SUB_1_ID, carrierId: Int): Intent = Intent(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED).apply { putExtra(EXTRA_SUBSCRIPTION_ID, subId) putExtra(EXTRA_CARRIER_ID, carrierId) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt index 573927552acc..7e27783a116e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt @@ -25,6 +25,9 @@ import android.app.Notification.VISIBILITY_PUBLIC import android.app.NotificationChannel import android.app.NotificationManager.IMPORTANCE_HIGH import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE +import android.app.role.OnRoleHoldersChangedListener +import android.app.role.RoleManager +import android.companion.AssociationRequest import android.content.pm.PackageManager import android.media.projection.MediaProjectionInfo import android.media.projection.MediaProjectionManager @@ -89,6 +92,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { @Mock private lateinit var activityManager: IActivityManager @Mock private lateinit var mediaProjectionManager: MediaProjectionManager @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var roleManager: RoleManager @Mock private lateinit var telephonyManager: TelephonyManager @Mock private lateinit var listener1: Runnable @Mock private lateinit var listener2: Runnable @@ -98,6 +102,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { private lateinit var executor: FakeExecutor private lateinit var globalSettings: FakeGlobalSettings private lateinit var mediaProjectionCallback: MediaProjectionManager.Callback + private lateinit var roleHolderCallback: OnRoleHoldersChangedListener private lateinit var controller: SensitiveNotificationProtectionControllerImpl private lateinit var mediaProjectionInfo: MediaProjectionInfo @@ -117,14 +122,14 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { whenever( packageManager.getPackageUidAsUser( TEST_PROJECTION_PACKAGE_NAME, - UserHandle.CURRENT.identifier + UserHandle.CURRENT.identifier, ) ) .thenReturn(TEST_PROJECTION_PACKAGE_UID) whenever( packageManager.getPackageUidAsUser( BUGREPORT_PACKAGE_NAME, - UserHandle.CURRENT.identifier + UserHandle.CURRENT.identifier, ) ) .thenReturn(BUGREPORT_PACKAGE_UID) @@ -134,7 +139,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { whenever( packageManager.getPackageUidAsUser( mContext.packageName, - UserHandle.CURRENT.identifier + UserHandle.CURRENT.identifier, ) ) .thenReturn(mContext.applicationInfo.uid) @@ -155,9 +160,10 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { activityManager, packageManager, telephonyManager, + roleManager, mockExecutorHandler(executor), executor, - logger + logger, ) // Process pending work (getting global setting and list of exemptions) @@ -167,6 +173,9 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { mediaProjectionCallback = withArgCaptor { verify(mediaProjectionManager).addCallback(capture(), any()) } + roleHolderCallback = withArgCaptor { + verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), capture(), any()) + } } @After @@ -307,7 +316,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { whenever( packageManager.checkPermission( android.Manifest.permission.RECORD_SENSITIVE_CONTENT, - mediaProjectionInfo.packageName + mediaProjectionInfo.packageName, ) ) .thenReturn(PackageManager.PERMISSION_GRANTED) @@ -322,7 +331,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { whenever( packageManager.checkPermission( android.Manifest.permission.RECORD_SENSITIVE_CONTENT, - mediaProjectionInfo.packageName + mediaProjectionInfo.packageName, ) ) .thenReturn(PackageManager.PERMISSION_GRANTED) @@ -340,6 +349,25 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { } @Test + fun isSensitiveStateActive_projectionActive_appStreamingRoleHolderExempt_false() { + setShareFullScreen() + whenever( + roleManager.getRoleHoldersAsUser( + AssociationRequest.DEVICE_PROFILE_APP_STREAMING, + mediaProjectionInfo.userHandle, + ) + ) + .thenReturn(listOf(TEST_PROJECTION_PACKAGE_NAME)) + roleHolderCallback.onRoleHoldersChanged( + AssociationRequest.DEVICE_PROFILE_APP_STREAMING, + mediaProjectionInfo.userHandle, + ) + mediaProjectionCallback.onStart(mediaProjectionInfo) + + assertFalse(controller.isSensitiveStateActive) + } + + @Test fun isSensitiveStateActive_projectionActive_disabledViaDevOption_false() { setDisabledViaDeveloperOption() mediaProjectionCallback.onStart(mediaProjectionInfo) @@ -449,7 +477,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { whenever( packageManager.checkPermission( android.Manifest.permission.RECORD_SENSITIVE_CONTENT, - mediaProjectionInfo.packageName + mediaProjectionInfo.packageName, ) ) .thenReturn(PackageManager.PERMISSION_GRANTED) @@ -466,7 +494,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { whenever( packageManager.checkPermission( android.Manifest.permission.RECORD_SENSITIVE_CONTENT, - mediaProjectionInfo.packageName + mediaProjectionInfo.packageName, ) ) .thenReturn(PackageManager.PERMISSION_GRANTED) @@ -528,7 +556,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(TEST_PROJECTION_PACKAGE_UID), eq(false), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } @@ -541,7 +569,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(TEST_PROJECTION_PACKAGE_UID), eq(false), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } } @@ -559,7 +587,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(TEST_PROJECTION_PACKAGE_UID), eq(true), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } @@ -572,7 +600,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(TEST_PROJECTION_PACKAGE_UID), eq(true), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } } @@ -590,7 +618,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(TEST_PROJECTION_PACKAGE_UID), eq(true), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } @@ -603,7 +631,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(TEST_PROJECTION_PACKAGE_UID), eq(true), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } } @@ -623,7 +651,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(mContext.applicationInfo.uid), eq(true), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } @@ -636,7 +664,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(mContext.applicationInfo.uid), eq(true), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } } @@ -654,7 +682,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(BUGREPORT_PACKAGE_UID), eq(true), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } @@ -667,7 +695,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { eq(BUGREPORT_PACKAGE_UID), eq(true), eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP), - eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI) + eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI), ) } } @@ -757,7 +785,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { return setupNotificationEntry( packageName, overrideVisibility = true, - overrideChannelVisibility = true + overrideChannelVisibility = true, ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 8d05ea16cfa6..44392420da49 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -465,9 +465,9 @@ public class VolumeDialogImplTest extends SysuiTestCase { public void notificationVolumeSeparated_theRingerIconChangesToSpeakerIcon() { // already separated. assert icon is new based on res id assertEquals(mDialog.mVolumeRingerIconDrawableId, - R.drawable.ic_speaker_on); + R.drawable.ic_legacy_speaker_on); assertEquals(mDialog.mVolumeRingerMuteIconDrawableId, - R.drawable.ic_speaker_mute); + R.drawable.ic_legacy_speaker_mute); } @Test diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/BatteryMeterViewControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/BatteryMeterViewControllerKosmos.kt new file mode 100644 index 000000000000..f3bccb126f62 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/BatteryMeterViewControllerKosmos.kt @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.battery + +import android.os.Handler +import android.test.mock.MockContentResolver +import com.android.systemui.flags.fake +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.settings.userTracker +import com.android.systemui.statusbar.policy.batteryController +import com.android.systemui.statusbar.policy.configurationController +import com.android.systemui.tuner.tunerService +import org.mockito.kotlin.mock + +val Kosmos.batteryMeterViewControllerFactory: BatteryMeterViewController.Factory by +Kosmos.Fixture { + BatteryMeterViewController.Factory( + userTracker, + configurationController, + tunerService, + mock<Handler>(), + MockContentResolver(), + featureFlagsClassic.fake, + batteryController + ) +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt index 0f21a16147f0..b8b2ec5a58ae 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.communal.domain.interactor +import android.content.pm.UserInfo import android.content.testableContext import android.os.userManager import com.android.systemui.broadcast.broadcastDispatcher @@ -85,27 +86,28 @@ fun Kosmos.setCommunalV2ConfigEnabled(enabled: Boolean) { ) } -suspend fun Kosmos.setCommunalEnabled(enabled: Boolean) { +suspend fun Kosmos.setCommunalEnabled(enabled: Boolean): UserInfo { fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, enabled) - if (enabled) { + return if (enabled) { fakeUserRepository.asMainUser() } else { fakeUserRepository.asDefaultUser() } } -suspend fun Kosmos.setCommunalV2Enabled(enabled: Boolean) { +suspend fun Kosmos.setCommunalV2Enabled(enabled: Boolean): UserInfo { setCommunalV2ConfigEnabled(enabled) - setCommunalEnabled(enabled) + return setCommunalEnabled(enabled) } -suspend fun Kosmos.setCommunalAvailable(available: Boolean) { - setCommunalEnabled(available) +suspend fun Kosmos.setCommunalAvailable(available: Boolean): UserInfo { + val user = setCommunalEnabled(available) fakeKeyguardRepository.setKeyguardShowing(available) fakeUserRepository.setUserUnlocked(FakeUserRepository.MAIN_USER_ID, available) + return user } -suspend fun Kosmos.setCommunalV2Available(available: Boolean) { +suspend fun Kosmos.setCommunalV2Available(available: Boolean): UserInfo { setCommunalV2ConfigEnabled(available) - setCommunalAvailable(available) + return setCommunalAvailable(available) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt index 93a59eb8ca0c..bdfa875f5429 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt @@ -16,6 +16,9 @@ package com.android.systemui.keyguard.domain.interactor +import com.android.systemui.communal.domain.interactor.communalInteractor +import com.android.systemui.communal.domain.interactor.communalSceneInteractor +import com.android.systemui.communal.domain.interactor.communalSettingsInteractor import com.android.systemui.deviceentry.data.repository.deviceEntryRepository import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.kosmos.Kosmos @@ -38,5 +41,8 @@ val Kosmos.fromAodTransitionInteractor by keyguardOcclusionInteractor = keyguardOcclusionInteractor, deviceEntryRepository = deviceEntryRepository, wakeToGoneInteractor = keyguardWakeDirectlyToGoneInteractor, + communalSettingsInteractor = communalSettingsInteractor, + communalSceneInteractor = communalSceneInteractor, + communalInteractor = communalInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..1eeecd4b7520 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGlanceableHubTransitionViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.glanceableHubBlurComponentFactory +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos + +val Kosmos.aodToGlanceableHubTransitionViewModel by + Kosmos.Fixture { + AodToGlanceableHubTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + blurFactory = glanceableHubBlurComponentFactory, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt index bd0045501ec8..2797b4409ff0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt @@ -47,5 +47,6 @@ val Kosmos.deviceEntryBackgroundViewModel by Fixture { primaryBouncerToLockscreenTransitionViewModel = primaryBouncerToLockscreenTransitionViewModel, lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel, + glanceableHubToAodTransitionViewModel = glanceableHubToAodTransitionViewModel, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..6004c7f2caec --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToAodTransitionViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos + +val Kosmos.glanceableHubToAodTransitionViewModel by + Kosmos.Fixture { + GlanceableHubToAodTransitionViewModel( + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index 78356318cbb4..27ca0f867855 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -94,5 +94,7 @@ val Kosmos.keyguardRootViewModel by Fixture { shadeInteractor = shadeInteractor, wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor, dumpManager = dumpManager, + glanceableHubToAodTransitionViewModel = glanceableHubToAodTransitionViewModel, + aodToGlanceableHubTransitionViewModel = aodToGlanceableHubTransitionViewModel, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt index 8d4db8b74061..8a6f68c5da68 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractorKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.qs.panels.domain.interactor +import com.android.internal.logging.uiEventLoggerFake import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.log.core.FakeLogBuffer @@ -29,6 +30,7 @@ val Kosmos.iconTilesInteractor by defaultLargeTilesRepository, currentTilesInteractor, qsPreferencesInteractor, + uiEventLoggerFake, largeTileSpanRepository, FakeLogBuffer.Factory.create(), applicationCoroutineScope, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/dialog/QSResetDialogDelegateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/dialog/QSResetDialogDelegateKosmos.kt index c58d55edd9e6..73d8dc6b48b5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/dialog/QSResetDialogDelegateKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/dialog/QSResetDialogDelegateKosmos.kt @@ -18,7 +18,14 @@ package com.android.systemui.qs.panels.ui.dialog import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.panels.domain.interactor.sizedTilesResetInteractor +import com.android.systemui.shade.data.repository.shadeDialogContextInteractor import com.android.systemui.statusbar.phone.systemUIDialogFactory val Kosmos.qsResetDialogDelegateKosmos by - Kosmos.Fixture { QSResetDialogDelegate(systemUIDialogFactory, sizedTilesResetInteractor) } + Kosmos.Fixture { + QSResetDialogDelegate( + systemUIDialogFactory, + shadeDialogContextInteractor, + sizedTilesResetInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt index 31be050adc98..4f662e0bbab2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsContainerViewModelKosmos.kt @@ -18,28 +18,37 @@ package com.android.systemui.qs.ui.viewmodel import com.android.systemui.brightness.ui.viewmodel.brightnessSliderViewModelFactory import com.android.systemui.kosmos.Kosmos +import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor +import com.android.systemui.media.controls.ui.controller.mediaCarouselController +import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.qs.panels.ui.viewmodel.detailsViewModel import com.android.systemui.qs.panels.ui.viewmodel.editModeViewModel import com.android.systemui.qs.panels.ui.viewmodel.tileGridViewModelFactory import com.android.systemui.qs.panels.ui.viewmodel.toolbar.toolbarViewModelFactory import com.android.systemui.shade.domain.interactor.shadeModeInteractor import com.android.systemui.shade.ui.viewmodel.shadeHeaderViewModelFactory +import org.mockito.kotlin.mock val Kosmos.quickSettingsContainerViewModelFactory by Kosmos.Fixture { object : QuickSettingsContainerViewModel.Factory { override fun create( - supportsBrightnessMirroring: Boolean + supportsBrightnessMirroring: Boolean, + expansion: Float?, ): QuickSettingsContainerViewModel { return QuickSettingsContainerViewModel( - brightnessSliderViewModelFactory, - shadeHeaderViewModelFactory, - tileGridViewModelFactory, - supportsBrightnessMirroring, - editModeViewModel, - detailsViewModel, - toolbarViewModelFactory, - shadeModeInteractor, + brightnessSliderViewModelFactory = brightnessSliderViewModelFactory, + shadeHeaderViewModelFactory = shadeHeaderViewModelFactory, + tileGridViewModelFactory = tileGridViewModelFactory, + supportsBrightnessMirroring = supportsBrightnessMirroring, + expansion = expansion, + editModeViewModel = editModeViewModel, + detailsViewModel = detailsViewModel, + toolbarViewModelFactory = toolbarViewModelFactory, + shadeModeInteractor = shadeModeInteractor, + mediaCarouselInteractor = mediaCarouselInteractor, + mediaCarouselController = mediaCarouselController, + mediaHost = mock<MediaHost>(), ) } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt index 60c0f342b874..f9917ac680e0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/shared/model/FakeSceneDataSource.kt @@ -44,6 +44,8 @@ class FakeSceneDataSource(initialSceneKey: SceneKey, val testScope: TestScope) : var pendingOverlays: Set<OverlayKey>? = null private set + var freezeAndAnimateToCurrentStateCallCount = 0 + override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) { if (_isPaused) { _pendingScene = toScene @@ -85,6 +87,10 @@ class FakeSceneDataSource(initialSceneKey: SceneKey, val testScope: TestScope) : hideOverlay(overlay) } + override fun freezeAndAnimateToCurrentState() { + freezeAndAnimateToCurrentStateCallCount++ + } + /** * Pauses scene and overlay changes. * diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeAnimationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeAnimationRepositoryKosmos.kt index 3ed730271bc3..e1ca86a03367 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeAnimationRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeAnimationRepositoryKosmos.kt @@ -18,12 +18,8 @@ package com.android.systemui.shade.data.repository import android.content.applicationContext import com.android.systemui.kosmos.Kosmos -import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock +import com.android.systemui.shade.domain.interactor.FakeShadeDialogContextInteractor val Kosmos.shadeAnimationRepository by Kosmos.Fixture { ShadeAnimationRepository() } val Kosmos.shadeDialogContextInteractor by - Kosmos.Fixture { - mock<ShadeDialogContextInteractor> { on { context } doReturn applicationContext } - } + Kosmos.Fixture { FakeShadeDialogContextInteractor(applicationContext) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt index ba7557ef7f71..26a441bc8ca3 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryKosmos.kt @@ -30,7 +30,6 @@ import com.android.systemui.shade.display.ShadeExpansionIntent import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy import com.android.systemui.shade.domain.interactor.notificationElement import com.android.systemui.shade.domain.interactor.qsElement -import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.util.settings.fakeGlobalSettings val Kosmos.defaultShadeDisplayPolicy: DefaultDisplayShadePolicy by @@ -49,9 +48,8 @@ val Kosmos.statusBarTouchShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy by StatusBarTouchShadeDisplayPolicy( displayRepository = displayRepository, backgroundScope = testScope.backgroundScope, - shadeInteractor = { shadeInteractor }, - notificationElement = { notificationElement }, qsShadeElement = { qsElement }, + notificationElement = { notificationElement }, ) } val Kosmos.shadeExpansionIntent: ShadeExpansionIntent by @@ -65,6 +63,7 @@ val Kosmos.shadeDisplaysRepository: ShadeDisplaysRepository by defaultPolicy = defaultShadeDisplayPolicy, shadeOnDefaultDisplayWhenLocked = true, keyguardRepository = keyguardRepository, + displayRepository = displayRepository, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt index 6fd7cf6edbe4..2ea2119970ad 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeHeaderClockInteractorKosmos.kt @@ -16,14 +16,18 @@ package com.android.systemui.shade.domain.interactor +import com.android.systemui.broadcast.broadcastDispatcher import com.android.systemui.kosmos.Kosmos import com.android.systemui.plugins.activityStarter import com.android.systemui.shade.data.repository.shadeHeaderClockRepository +import com.android.systemui.util.time.systemClock var Kosmos.shadeHeaderClockInteractor: ShadeHeaderClockInteractor by Kosmos.Fixture { ShadeHeaderClockInteractor( repository = shadeHeaderClockRepository, activityStarter = activityStarter, + broadcastDispatcher = broadcastDispatcher, + systemClock = systemClock, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt index cfc2075c1352..34e5bfde43c9 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelKosmos.kt @@ -17,8 +17,7 @@ package com.android.systemui.shade.ui.viewmodel import android.content.applicationContext -import com.android.systemui.battery.BatteryMeterViewController -import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.battery.batteryMeterViewControllerFactory import com.android.systemui.kosmos.Kosmos import com.android.systemui.plugins.activityStarter import com.android.systemui.scene.domain.interactor.sceneInteractor @@ -26,9 +25,8 @@ import com.android.systemui.shade.domain.interactor.privacyChipInteractor import com.android.systemui.shade.domain.interactor.shadeHeaderClockInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.domain.interactor.shadeModeInteractor -import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerStatusBarViewBinder import com.android.systemui.statusbar.phone.ui.StatusBarIconController -import com.android.systemui.statusbar.phone.ui.TintedIconManager +import com.android.systemui.statusbar.phone.ui.tintedIconManagerFactory import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.mobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.mobileIconsViewModel import org.mockito.kotlin.mock @@ -45,12 +43,9 @@ val Kosmos.shadeHeaderViewModel: ShadeHeaderViewModel by mobileIconsViewModel = mobileIconsViewModel, privacyChipInteractor = privacyChipInteractor, clockInteractor = shadeHeaderClockInteractor, - tintedIconManagerFactory = mock<TintedIconManager.Factory>(), - batteryMeterViewControllerFactory = mock<BatteryMeterViewController.Factory>(), + tintedIconManagerFactory = tintedIconManagerFactory, + batteryMeterViewControllerFactory = batteryMeterViewControllerFactory, statusBarIconController = mock<StatusBarIconController>(), - notificationIconContainerStatusBarViewBinder = - mock<NotificationIconContainerStatusBarViewBinder>(), - broadcastDispatcher = broadcastDispatcher, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt index 878c2deb43b2..d8e0cfe4fbf8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelKosmos.kt @@ -21,6 +21,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor +import com.android.systemui.util.time.fakeSystemClock val Kosmos.notifChipsViewModel: NotifChipsViewModel by Kosmos.Fixture { @@ -29,5 +30,6 @@ val Kosmos.notifChipsViewModel: NotifChipsViewModel by applicationCoroutineScope, statusBarNotificationChipsInteractor, headsUpNotificationInteractor, + fakeSystemClock, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderKosmos.kt new file mode 100644 index 000000000000..18d65206767e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderKosmos.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.connectivity.ui + +import com.android.systemui.kosmos.Kosmos +import org.mockito.kotlin.mock + +// NOTE: `mobileContextProvider` is a mock instance. +val Kosmos.mobileContextProvider by +Kosmos.Fixture { + mock<MobileContextProvider>() +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt index 93502f365202..b876095fefe5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt @@ -17,13 +17,14 @@ package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.mediaControlChipViewModel -val Kosmos.statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel by +private val Kosmos.statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel by + Kosmos.Fixture { StatusBarPopupChipsViewModel(mediaControlChip = mediaControlChipViewModel) } + +val Kosmos.statusBarPopupChipsViewModelFactory by Kosmos.Fixture { - StatusBarPopupChipsViewModel( - testScope.backgroundScope, - mediaControlChipViewModel = mediaControlChipViewModel, - ) + object : StatusBarPopupChipsViewModel.Factory { + override fun create(): StatusBarPopupChipsViewModel = statusBarPopupChipsViewModel + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationEntryBuilderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationEntryBuilderKosmos.kt new file mode 100644 index 000000000000..59f5ecd2563f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationEntryBuilderKosmos.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification + +import android.app.Notification +import android.app.PendingIntent +import android.app.Person +import android.content.Intent +import android.content.applicationContext +import android.graphics.drawable.Icon +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder +import com.android.systemui.statusbar.notification.icon.IconPack +import com.android.systemui.statusbar.notification.promoted.setPromotedContent +import org.mockito.kotlin.mock + +fun Kosmos.setIconPackWithMockIconViews(entry: NotificationEntry) { + entry.icons = + IconPack.buildPack( + /* statusBarIcon = */ mock(), + /* statusBarChipIcon = */ mock(), + /* shelfIcon = */ mock(), + /* aodIcon = */ mock(), + /* source = */ null, + ) +} + +fun Kosmos.buildOngoingCallEntry( + promoted: Boolean = false, + block: NotificationEntryBuilder.() -> Unit = {}, +): NotificationEntry = + buildNotificationEntry( + tag = "call", + promoted = promoted, + style = makeOngoingCallStyle(), + block = block, + ) + +fun Kosmos.buildPromotedOngoingEntry( + block: NotificationEntryBuilder.() -> Unit = {} +): NotificationEntry = + buildNotificationEntry(tag = "ron", promoted = true, style = null, block = block) + +fun Kosmos.buildNotificationEntry( + tag: String? = null, + promoted: Boolean = false, + style: Notification.Style? = null, + block: NotificationEntryBuilder.() -> Unit = {}, +): NotificationEntry = + NotificationEntryBuilder() + .apply { + setTag(tag) + setFlag(applicationContext, Notification.FLAG_PROMOTED_ONGOING, promoted) + modifyNotification(applicationContext) + .setSmallIcon(Icon.createWithContentUri("content://null")) + .setStyle(style) + } + .apply(block) + .build() + .also { + setIconPackWithMockIconViews(it) + if (promoted) setPromotedContent(it) + } + +private fun Kosmos.makeOngoingCallStyle(): Notification.CallStyle { + val pendingIntent = + PendingIntent.getBroadcast( + applicationContext, + 0, + Intent("action"), + PendingIntent.FLAG_IMMUTABLE, + ) + val person = Person.Builder().setName("person").build() + return Notification.CallStyle.forOngoingCall(person, pendingIntent) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt index a48b27015c02..fa3702cea5ee 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/NotifPipelineKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection import com.android.systemui.kosmos.Kosmos -import com.android.systemui.util.mockito.mock +import org.mockito.kotlin.mock -var Kosmos.notifPipeline by Kosmos.Fixture { mock<NotifPipeline>() } +var Kosmos.notifPipeline by Kosmos.Fixture { mockNotifPipeline } +var Kosmos.mockNotifPipeline by Kosmos.Fixture { mock<NotifPipeline>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt index 63521de096c9..da879d9e314d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt @@ -16,15 +16,31 @@ package com.android.systemui.statusbar.notification.promoted +import android.app.Notification import android.content.applicationContext import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.row.RowImageInflater import com.android.systemui.statusbar.notification.row.shared.skeletonImageTransform +import com.android.systemui.util.time.systemClock var Kosmos.promotedNotificationContentExtractor by Kosmos.Fixture { PromotedNotificationContentExtractorImpl( applicationContext, skeletonImageTransform, + systemClock, promotedNotificationLogger, ) } + +fun Kosmos.setPromotedContent(entry: NotificationEntry) { + val extractedContent = + promotedNotificationContentExtractor.extractContent( + entry, + Notification.Builder.recoverBuilder(applicationContext, entry.sbn.notification), + RowImageInflater.newInstance(null).useForContentModel(), + ) + entry.promotedNotificationContentModel = + requireNotNull(extractedContent) { "extractContent returned null" } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt index df1c82278bc2..fcd484353011 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractorKosmos.kt @@ -18,12 +18,11 @@ package com.android.systemui.statusbar.notification.promoted.domain.interactor import com.android.systemui.dump.dumpManager import com.android.systemui.kosmos.Kosmos -import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor val Kosmos.aodPromotedNotificationInteractor by Kosmos.Fixture { AODPromotedNotificationInteractor( - activeNotificationsInteractor = activeNotificationsInteractor, + promotedNotificationsInteractor = promotedNotificationsInteractor, dumpManager = dumpManager, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorKosmos.kt new file mode 100644 index 000000000000..093ec10e2642 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorKosmos.kt @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.promoted.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.statusbar.chips.call.domain.interactor.callChipInteractor +import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor +import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor + +val Kosmos.promotedNotificationsInteractor by + Kosmos.Fixture { + PromotedNotificationsInteractor( + activeNotificationsInteractor = activeNotificationsInteractor, + callChipInteractor = callChipInteractor, + notifChipsInteractor = statusBarNotificationChipsInteractor, + backgroundDispatcher = testDispatcher, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt index e445a73b06d0..09c632cf61fd 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt @@ -41,6 +41,7 @@ import com.android.systemui.media.controls.util.MediaFeatureFlag import com.android.systemui.media.dialog.MediaOutputDialogManager import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.settings.UserTracker import com.android.systemui.shared.system.ActivityManagerWrapper import com.android.systemui.shared.system.DevicePolicyManagerWrapper import com.android.systemui.shared.system.PackageManagerWrapper @@ -227,6 +228,7 @@ class ExpandableNotificationRowBuilder( PromotedNotificationContentExtractorImpl( context, SkeletonImageTransform(context), + mFakeSystemClock, PromotedNotificationLogger(logcatLogBuffer("PromotedNotifLog")), ) @@ -346,10 +348,15 @@ class ExpandableNotificationRowBuilder( // NOTE: This flag is read when the ExpandableNotificationRow is inflated, so it needs to be // set, but we do not want to override an existing value that is needed by a specific test. + val userTracker = Mockito.mock(UserTracker::class.java, STUB_ONLY) + whenever(userTracker.userHandle).thenReturn(context.user) + val rowInflaterTask = RowInflaterTask( mFakeSystemClock, Mockito.mock(RowInflaterTaskLogger::class.java, STUB_ONLY), + userTracker, + Mockito.mock(AsyncRowInflater::class.java, STUB_ONLY), ) val row = rowInflaterTask.inflateSynchronously(context, null, entry) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt index bc1363ac3d5c..970b87cd368a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinderKosmos.kt @@ -33,7 +33,7 @@ import java.util.Optional val Kosmos.notificationListViewBinder by Fixture { NotificationListViewBinder( - backgroundDispatcher = testDispatcher, + inflationDispatcher = testDispatcher, hiderTracker = displaySwitchNotificationsHiderTracker, configuration = configurationState, falsingManager = falsingManager, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt index 7a2b7c24252b..51bb94fd2ab9 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt @@ -25,15 +25,18 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.aodBurnInViewModel +import com.android.systemui.keyguard.ui.viewmodel.aodToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.aodToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.aodToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.aodToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.aodToPrimaryBouncerTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.dozingToDreamingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.dozingToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.dozingToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.dozingToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.dozingToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.dreamingToLockscreenTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.goneToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.goneToDozingTransitionViewModel @@ -81,6 +84,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture { aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel, aodToOccludedTransitionViewModel = aodToOccludedTransitionViewModel, aodToPrimaryBouncerTransitionViewModel = aodToPrimaryBouncerTransitionViewModel, + dozingToDreamingTransitionViewModel = dozingToDreamingTransitionViewModel, dozingToGlanceableHubTransitionViewModel = dozingToGlanceableHubTransitionViewModel, dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel, dozingToOccludedTransitionViewModel = dozingToOccludedTransitionViewModel, @@ -110,5 +114,7 @@ val Kosmos.sharedNotificationContainerViewModel by Fixture { headsUpNotificationInteractor = { headsUpNotificationInteractor }, largeScreenHeaderHelperLazy = { largeScreenHeaderHelper }, unfoldTransitionInteractor = unfoldTransitionInteractor, + glanceableHubToAodTransitionViewModel = glanceableHubToAodTransitionViewModel, + aodToGlanceableHubTransitionViewModel = aodToGlanceableHubTransitionViewModel, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt index d787e2c190c8..91404e0688ed 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt @@ -30,6 +30,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.plugins.activityStarter import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.settings.userTracker +import com.android.systemui.shade.data.repository.shadeDialogContextInteractor import com.android.systemui.shade.domain.interactor.panelExpansionInteractor import com.android.systemui.shade.domain.interactor.shadeAnimationInteractor import com.android.systemui.shade.shadeController @@ -52,6 +53,7 @@ val Kosmos.statusBarNotificationActivityStarter by Kosmos.Fixture { StatusBarNotificationActivityStarter( applicationContext, + shadeDialogContextInteractor, fakeExecutorHandler, fakeExecutor, notificationVisibilityProvider, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/DisableChipsModernization.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/DisableChipsModernization.kt new file mode 100644 index 000000000000..69eecc0f082b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/DisableChipsModernization.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone.ongoingcall + +import android.platform.test.annotations.DisableFlags + +/** Disables all the flags necessary for [StatusBarChipsModernization.isEnabled] to return false. */ +@DisableFlags(StatusBarChipsModernization.FLAG_NAME) +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +annotation class DisableChipsModernization diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/EnableChipsModernization.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/EnableChipsModernization.kt new file mode 100644 index 000000000000..caa4373a2037 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ongoingcall/EnableChipsModernization.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone.ongoingcall + +import android.platform.test.annotations.EnableFlags +import com.android.systemui.statusbar.core.StatusBarRootModernization + +/** Enables all the flags necessary for [StatusBarChipsModernization.isEnabled] to return true. */ +@EnableFlags(StatusBarChipsModernization.FLAG_NAME, StatusBarRootModernization.FLAG_NAME) +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +annotation class EnableChipsModernization diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerKosmos.kt new file mode 100644 index 000000000000..0a387f860a5b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerKosmos.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone.ui + +import com.android.systemui.kosmos.Kosmos +import org.mockito.kotlin.mock + +// NOTE: `statusBarIconController` is a mock instance. +val Kosmos.statusBarIconController by Kosmos.Fixture { + mock<StatusBarIconControllerImpl>() +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ui/TintedIconManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ui/TintedIconManagerKosmos.kt new file mode 100644 index 000000000000..8e13b624f5fa --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/ui/TintedIconManagerKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone.ui + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.connectivity.ui.mobileContextProvider +import com.android.systemui.statusbar.pipeline.mobile.ui.mobileUiAdapter +import com.android.systemui.statusbar.pipeline.wifi.ui.wifiUiAdapter + +val Kosmos.tintedIconManagerFactory by +Kosmos.Fixture { + TintedIconManager.Factory( + wifiUiAdapter, + mobileUiAdapter, + mobileContextProvider, + ) +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelKosmos.kt new file mode 100644 index 000000000000..50895459cda0 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.airplane.ui.viewmodel + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.backgroundScope +import com.android.systemui.log.table.logcatTableLogBuffer +import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.airplaneModeInteractor + +val Kosmos.airplaneModeViewModel by Kosmos.Fixture { + AirplaneModeViewModelImpl( + airplaneModeInteractor, + logcatTableLogBuffer(this, "AirplaneModeTableLogBuffer"), + backgroundScope, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapterKosmos.kt new file mode 100644 index 000000000000..a87d3b0538fd --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapterKosmos.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.mobile.ui + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.statusbar.phone.ui.statusBarIconController +import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.mobileIconsViewModel + +val Kosmos.mobileUiAdapter by + Kosmos.Fixture { + MobileUiAdapter( + statusBarIconController, + mobileIconsViewModel, + mobileViewLogger, + applicationCoroutineScope, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerKosmos.kt new file mode 100644 index 000000000000..206ecd332c37 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLoggerKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.mobile.ui + +import com.android.systemui.kosmos.Kosmos +import org.mockito.kotlin.mock + +// NOTE: `mobileViewLogger` is a mock instance. +val Kosmos.mobileViewLogger by Kosmos.Fixture { mock<MobileViewLogger>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt index fbada934c9d4..a97c651ba426 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt @@ -29,7 +29,7 @@ import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel import com.android.systemui.statusbar.events.domain.interactor.systemStatusEventAnimationInteractor -import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModel +import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModelFactory import com.android.systemui.statusbar.layout.ui.viewmodel.multiDisplayStatusBarContentInsetsViewModelStore import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor @@ -59,7 +59,7 @@ var Kosmos.homeStatusBarViewModel: HomeStatusBarViewModel by shadeInteractor, shareToAppChipViewModel, ongoingActivityChipsViewModel, - statusBarPopupChipsViewModel, + statusBarPopupChipsViewModelFactory, systemStatusEventAnimationInteractor, multiDisplayStatusBarContentInsetsViewModelStore, backgroundScope, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapterKosmos.kt new file mode 100644 index 000000000000..d4d589663477 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/WifiUiAdapterKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.wifi.ui + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.phone.ui.statusBarIconController +import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.wifiViewModel + +val Kosmos.wifiUiAdapter by + Kosmos.Fixture { + WifiUiAdapter( + statusBarIconController, + wifiViewModel, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelKosmos.kt new file mode 100644 index 000000000000..3f876ef0536b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelKosmos.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.pipeline.wifi.ui.viewmodel + +import android.content.applicationContext +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.log.table.logcatTableLogBuffer +import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.airplaneModeViewModel +import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants +import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.wifiInteractor +import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants +import kotlinx.coroutines.flow.flowOf +import org.mockito.kotlin.mock + +val Kosmos.wifiViewModel by + Kosmos.Fixture { + WifiViewModel( + airplaneModeViewModel, + { flowOf(false) }, + mock<ConnectivityConstants>(), + applicationContext, + logcatTableLogBuffer(this, "WifiViewModelTest"), + wifiInteractor, + applicationCoroutineScope, + mock<WifiConstants>(), + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt index a209ec9d0c9c..b23ccbfbd93f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/time/FakeSystemClockKosmos.kt @@ -14,19 +14,23 @@ * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.util.time import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.currentTime -val Kosmos.systemClock by +var Kosmos.systemClock by Kosmos.Fixture<SystemClock> { mock { whenever(elapsedRealtime()).thenAnswer { testScope.currentTime } whenever(uptimeMillis()).thenAnswer { testScope.currentTime } + whenever(currentTimeMillis()).thenAnswer { testScope.currentTime } } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt index 386e0feb3b3a..54118844effc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinderKosmos.kt @@ -16,6 +16,7 @@ package com.android.systemui.volume.dialog.ui.binder +import android.content.applicationContext import com.android.systemui.kosmos.Kosmos import com.android.systemui.volume.dialog.ringer.volumeDialogRingerViewBinder import com.android.systemui.volume.dialog.settings.ui.binder.volumeDialogSettingsButtonViewBinder @@ -27,6 +28,7 @@ import com.android.systemui.volume.dialog.utils.volumeTracer val Kosmos.volumeDialogViewBinder by Kosmos.Fixture { VolumeDialogViewBinder( + applicationContext, volumeDialogViewModel, jankListenerFactory, volumeTracer, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt index aeff86ed89bb..24d2f1f0d901 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperFocalAreaRepository.kt @@ -34,12 +34,15 @@ class FakeWallpaperFocalAreaRepository : WallpaperFocalAreaRepository { _wallpaperFocalAreaBounds.asStateFlow() private val _wallpaperFocalAreaTapPosition = MutableStateFlow(PointF(0F, 0F)) - override val wallpaperFocalAreaTapPosition: StateFlow<PointF> = + val wallpaperFocalAreaTapPosition: StateFlow<PointF> = _wallpaperFocalAreaTapPosition.asStateFlow() private val _notificationDefaultTop = MutableStateFlow(0F) override val notificationDefaultTop: StateFlow<Float> = _notificationDefaultTop.asStateFlow() + private val _hasFocalArea = MutableStateFlow(false) + override val hasFocalArea: StateFlow<Boolean> = _hasFocalArea.asStateFlow() + override fun setShortcutAbsoluteTop(top: Float) { _shortcutAbsoluteTop.value = top } @@ -56,7 +59,7 @@ class FakeWallpaperFocalAreaRepository : WallpaperFocalAreaRepository { _wallpaperFocalAreaBounds.value = bounds } - override fun setTapPosition(point: PointF) { - _wallpaperFocalAreaTapPosition.value = point + override fun setTapPosition(tapPosition: PointF) { + _wallpaperFocalAreaTapPosition.value = tapPosition } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt index 8689e04e62dd..66bb803c182d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/FakeWallpaperRepository.kt @@ -17,6 +17,8 @@ package com.android.systemui.wallpapers.data.repository import android.app.WallpaperInfo +import android.graphics.PointF +import android.graphics.RectF import android.view.View import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -34,9 +36,9 @@ class FakeWallpaperRepository : WallpaperRepository { private val _shouldSendFocalArea = MutableStateFlow(false) override val shouldSendFocalArea: StateFlow<Boolean> = _shouldSendFocalArea.asStateFlow() - fun setShouldSendFocalArea(shouldSendFocalArea: Boolean) { - _shouldSendFocalArea.value = shouldSendFocalArea - } + override fun sendLockScreenLayoutChangeCommand(wallpaperFocalAreaBounds: RectF) {} + + override fun sendTapCommand(tapPosition: PointF) {} fun setWallpaperInfo(wallpaperInfo: WallpaperInfo?) { _wallpaperInfo.value = wallpaperInfo diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt index 7ebec6c3a7b9..1761503b2cc9 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/data/repository/WallpaperRepositoryKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.wallpapers.data.repository import android.content.applicationContext import com.android.app.wallpaperManager import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testDispatcher @@ -34,8 +33,6 @@ val Kosmos.wallpaperRepository by Fixture { bgDispatcher = testDispatcher, broadcastDispatcher = broadcastDispatcher, userRepository = userRepository, - keyguardTransitionInteractor = keyguardTransitionInteractor, - wallpaperFocalAreaRepository = wallpaperFocalAreaRepository, wallpaperManager = wallpaperManager, secureSettings = fakeSettings, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt index 88eb5511160b..eaf55a72be93 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/domain/interactor/WallpaperFocalAreaInteractor.kt @@ -18,20 +18,14 @@ package com.android.systemui.wallpapers.domain.interactor import android.content.applicationContext import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.shade.data.repository.shadeRepository -import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.wallpapers.data.repository.wallpaperFocalAreaRepository -import com.android.systemui.wallpapers.data.repository.wallpaperRepository -val Kosmos.wallpaperFocalAreaInteractor by +var Kosmos.wallpaperFocalAreaInteractor by Kosmos.Fixture { WallpaperFocalAreaInteractor( - applicationScope = applicationCoroutineScope, context = applicationContext, wallpaperFocalAreaRepository = wallpaperFocalAreaRepository, shadeRepository = shadeRepository, - activeNotificationsInteractor = activeNotificationsInteractor, - wallpaperRepository = wallpaperRepository, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt index 7e232c526732..4032503d04c1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/wallpapers/ui/viewmodel/WallpaperFocalAreaViewModel.kt @@ -16,10 +16,14 @@ package com.android.systemui.wallpapers.ui.viewmodel +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.wallpapers.domain.interactor.wallpaperFocalAreaInteractor var Kosmos.wallpaperFocalAreaViewModel by Kosmos.Fixture { - WallpaperFocalAreaViewModel(wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor) + WallpaperFocalAreaViewModel( + wallpaperFocalAreaInteractor = wallpaperFocalAreaInteractor, + keyguardTransitionInteractor = keyguardTransitionInteractor, + ) } diff --git a/packages/Vcn/TEST_MAPPING b/packages/Vcn/TEST_MAPPING index 9722a838ab8e..9ca5304eb8d9 100644 --- a/packages/Vcn/TEST_MAPPING +++ b/packages/Vcn/TEST_MAPPING @@ -14,5 +14,13 @@ { "name": "CtsVcnTestCases" } + ], + "tethering-mainline-presubmit": [ + { + "name": "FrameworksVcnTests" + }, + { + "name": "CtsVcnTestCases" + } ] }
\ No newline at end of file diff --git a/packages/Vcn/framework-b/Android.bp b/packages/Vcn/framework-b/Android.bp index edb22c0e7aa0..c53123359872 100644 --- a/packages/Vcn/framework-b/Android.bp +++ b/packages/Vcn/framework-b/Android.bp @@ -77,8 +77,7 @@ framework_connectivity_b_defaults_soong_config { ], soong_config_variables: { is_vcn_in_mainline: { - //TODO: b/380155299 Make it Baklava when aidl tool can understand it - min_sdk_version: "current", + min_sdk_version: "36", static_libs: ["android.net.vcn.flags-aconfig-java"], apex_available: ["com.android.tethering"], diff --git a/ravenwood/TEST_MAPPING b/ravenwood/TEST_MAPPING index cb54e9f56c0c..df63cb9dfc50 100644 --- a/ravenwood/TEST_MAPPING +++ b/ravenwood/TEST_MAPPING @@ -2,6 +2,7 @@ "presubmit": [ { "name": "tiny-framework-dump-test" }, { "name": "hoststubgentest" }, + { "name": "ravenhelpertest" }, { "name": "hoststubgen-test-tiny-test" }, { "name": "hoststubgen-invoke-test" }, { "name": "RavenwoodMockitoTest_device" }, diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java new file mode 100644 index 000000000000..7ee9d7a8a5c6 --- /dev/null +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodMethodCallLogger.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.platform.test.ravenwood; + +import com.android.ravenwood.RavenwoodRuntimeNative; + +import java.io.PrintStream; +import java.util.HashSet; +import java.util.Objects; + +/** + * Provides a method call hook that prints almost all (see below) the framework methods being + * called with indentation. + * + * We don't log methods that are trivial, uninteresting, or would be too noisy. + * e.g. we don't want to log any logging related methods, or collection APIs. + * + */ +public class RavenwoodMethodCallLogger { + private RavenwoodMethodCallLogger() { + } + + /** We don't want to log anything before ravenwood is initialized. This flag controls it.*/ + private static volatile boolean sEnabled = false; + + private static volatile PrintStream sOut = System.out; + + /** Return the current thread's call nest level. */ + private static int getNestLevel() { + return Thread.currentThread().getStackTrace().length; + } + + private static class ThreadInfo { + /** + * We save the current thread's nest call level here and use that as the initial level. + * We do it because otherwise the nest level would be too deep by the time test + * starts. + */ + public final int mInitialNestLevel = getNestLevel(); + + /** + * A nest level where shouldLog() returned false. + * Once it's set, we ignore all calls deeper than this. + */ + public int mDisabledNestLevel = Integer.MAX_VALUE; + } + + private static final ThreadLocal<ThreadInfo> sThreadInfo = new ThreadLocal<>() { + @Override + protected ThreadInfo initialValue() { + return new ThreadInfo(); + } + }; + + /** Classes that should be logged. Uses a map for fast lookup. */ + private static final HashSet<Class> sIgnoreClasses = new HashSet<>(); + static { + // The following classes are not interesting... + sIgnoreClasses.add(android.util.Log.class); + sIgnoreClasses.add(android.util.Slog.class); + sIgnoreClasses.add(android.util.EventLog.class); + sIgnoreClasses.add(android.util.TimingsTraceLog.class); + + sIgnoreClasses.add(android.util.SparseArray.class); + sIgnoreClasses.add(android.util.SparseIntArray.class); + sIgnoreClasses.add(android.util.SparseLongArray.class); + sIgnoreClasses.add(android.util.SparseBooleanArray.class); + sIgnoreClasses.add(android.util.SparseDoubleArray.class); + sIgnoreClasses.add(android.util.SparseSetArray.class); + sIgnoreClasses.add(android.util.SparseArrayMap.class); + sIgnoreClasses.add(android.util.LongSparseArray.class); + sIgnoreClasses.add(android.util.LongSparseLongArray.class); + sIgnoreClasses.add(android.util.LongArray.class); + + sIgnoreClasses.add(android.text.FontConfig.class); + + sIgnoreClasses.add(android.os.SystemClock.class); + sIgnoreClasses.add(android.os.Trace.class); + sIgnoreClasses.add(android.os.LocaleList.class); + sIgnoreClasses.add(android.os.Build.class); + sIgnoreClasses.add(android.os.SystemProperties.class); + + sIgnoreClasses.add(com.android.internal.util.Preconditions.class); + + sIgnoreClasses.add(android.graphics.FontListParser.class); + sIgnoreClasses.add(android.graphics.ColorSpace.class); + + sIgnoreClasses.add(android.graphics.fonts.FontStyle.class); + sIgnoreClasses.add(android.graphics.fonts.FontVariationAxis.class); + + sIgnoreClasses.add(com.android.internal.compat.CompatibilityChangeInfo.class); + sIgnoreClasses.add(com.android.internal.os.LoggingPrintStream.class); + + sIgnoreClasses.add(android.os.ThreadLocalWorkSource.class); + + // Following classes *may* be interesting for some purposes, but the initialization is + // too noisy... + sIgnoreClasses.add(android.graphics.fonts.SystemFonts.class); + + } + + /** + * Return if a class should be ignored. Uses {link #sIgnoreCladsses}, but + * we ignore more classes. + */ + private static boolean shouldIgnoreClass(Class<?> clazz) { + if (sIgnoreClasses.contains(clazz)) { + return true; + } + // Let's also ignore collection-ish classes in android.util. + if (java.util.Collection.class.isAssignableFrom(clazz) + || java.util.Map.class.isAssignableFrom(clazz) + ) { + if ("android.util".equals(clazz.getPackageName())) { + return true; + } + return false; + } + + switch (clazz.getSimpleName()) { + case "EventLogTags": + return false; + } + + // Following are classes that can't be referred to here directly. + // e.g. AndroidPrintStream is package-private, so we can't use its "class" here. + switch (clazz.getName()) { + case "com.android.internal.os.AndroidPrintStream": + return false; + } + return false; + } + + private static boolean shouldLog( + Class<?> methodClass, + String methodName, + @SuppressWarnings("UnusedVariable") String methodDescriptor + ) { + // Should we ignore this class? + if (shouldIgnoreClass(methodClass)) { + return false; + } + // Is it a nested class in a class that should be ignored? + var host = methodClass.getNestHost(); + if (host != methodClass && shouldIgnoreClass(host)) { + return false; + } + + var className = methodClass.getName(); + + // Ad-hoc ignore list. They'd be too noisy. + if ("create".equals(methodName) + // We may apply jarjar, so use endsWith(). + && className.endsWith("com.android.server.compat.CompatConfig")) { + return false; + } + + var pkg = methodClass.getPackageName(); + if (pkg.startsWith("android.icu")) { + return false; + } + + return true; + } + + /** + * Call this to enable logging. + */ + public static void enable(PrintStream out) { + sEnabled = true; + sOut = Objects.requireNonNull(out); + + // It's called from the test thread (Java's main thread). Because we're already + // in deep nest calls, we initialize the initial nest level here. + sThreadInfo.get(); + } + + /** Actual method hook entry point.*/ + public static void logMethodCall( + Class<?> methodClass, + String methodName, + String methodDescriptor + ) { + if (!sEnabled) { + return; + } + final var ti = sThreadInfo.get(); + final int nestLevel = getNestLevel() - ti.mInitialNestLevel; + + // Once shouldLog() returns false, we just ignore all deeper calls. + if (ti.mDisabledNestLevel < nestLevel) { + return; // Still ignore. + } + final boolean shouldLog = shouldLog(methodClass, methodName, methodDescriptor); + + if (!shouldLog) { + ti.mDisabledNestLevel = nestLevel; + return; + } + ti.mDisabledNestLevel = Integer.MAX_VALUE; + + var out = sOut; + out.print("# ["); + out.print(RavenwoodRuntimeNative.gettid()); + out.print(": "); + out.print(Thread.currentThread().getName()); + out.print("]: "); + out.print("[@"); + out.printf("%2d", nestLevel); + out.print("] "); + for (int i = 0; i < nestLevel; i++) { + out.print(" "); + } + out.println(methodClass.getName() + "." + methodName + methodDescriptor); + } +} diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java index 7af03ed2e6c8..ae88bb234e9d 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java @@ -23,7 +23,6 @@ import static android.platform.test.ravenwood.RavenwoodSystemServer.ANDROID_PACK import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_EMPTY_RESOURCES_APK; import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_INST_RESOURCE_APK; import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK; -import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING; import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERSION_JAVA_SYSPROP; import static com.android.ravenwood.common.RavenwoodCommonUtils.parseNullableInt; import static com.android.ravenwood.common.RavenwoodCommonUtils.withDefault; @@ -103,6 +102,10 @@ public class RavenwoodRuntimeEnvironmentController { private RavenwoodRuntimeEnvironmentController() { } + private static final PrintStream sStdOut = System.out; + @SuppressWarnings("UnusedVariable") + private static final PrintStream sStdErr = System.err; + private static final String MAIN_THREAD_NAME = "RavenwoodMain"; private static final String LIBRAVENWOOD_INITIALIZER_NAME = "ravenwood_initializer"; private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime"; @@ -212,9 +215,9 @@ public class RavenwoodRuntimeEnvironmentController { } private static void globalInitInner() throws IOException { - if (RAVENWOOD_VERBOSE_LOGGING) { - Log.v(TAG, "globalInit() called here...", new RuntimeException("NOT A CRASH")); - } + // We haven't initialized liblog yet, so directly write to System.out here. + RavenwoodCommonUtils.log(TAG, "globalInitInner()"); + if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) { Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler); } @@ -234,9 +237,6 @@ public class RavenwoodRuntimeEnvironmentController { dumpJavaProperties(); dumpOtherInfo(); - // We haven't initialized liblog yet, so directly write to System.out here. - RavenwoodCommonUtils.log(TAG, "globalInitInner()"); - // Make sure libravenwood_runtime is loaded. System.load(RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_RUNTIME_NAME)); @@ -261,6 +261,9 @@ public class RavenwoodRuntimeEnvironmentController { // Make sure libandroid_runtime is loaded. RavenwoodNativeLoader.loadFrameworkNativeCode(); + // Start method logging. + RavenwoodMethodCallLogger.enable(sStdOut); + // Touch some references early to ensure they're <clinit>'ed Objects.requireNonNull(Build.TYPE); Objects.requireNonNull(Build.VERSION.SDK); diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh index 27c5ea1bd0d7..67ebb1fc9473 100755 --- a/ravenwood/scripts/run-ravenwood-tests.sh +++ b/ravenwood/scripts/run-ravenwood-tests.sh @@ -66,7 +66,7 @@ esac done shift $(($OPTIND - 1)) -all_tests=(hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test ravenwood-stats-checker) +all_tests=(hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test ravenwood-stats-checker ravenhelpertest) all_tests+=( $(${0%/*}/list-ravenwood-tests.sh) ) filter() { diff --git a/ravenwood/texts/ravenwood-standard-options.txt b/ravenwood/texts/ravenwood-standard-options.txt index 91fd9283aff2..0edc348fc7f2 100644 --- a/ravenwood/texts/ravenwood-standard-options.txt +++ b/ravenwood/texts/ravenwood-standard-options.txt @@ -9,8 +9,10 @@ # Uncomment below lines to enable each feature. +# Enable method call hook. #--default-method-call-hook -# com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall +# android.platform.test.ravenwood.RavenwoodMethodCallLogger.logMethodCall + #--default-class-load-hook # com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded diff --git a/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java index 78fd8f7f960a..145325ccc809 100644 --- a/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java +++ b/ravenwood/tools/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java @@ -18,6 +18,7 @@ package com.android.hoststubgen.hosthelper; import java.io.PrintStream; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Arrays; /** * Utilities used in the host side test environment. @@ -36,9 +37,14 @@ public class HostTestUtils { public static final String CLASS_INTERNAL_NAME = getInternalName(HostTestUtils.class); + /** If true, we skip all method call hooks */ + private static final boolean SKIP_METHOD_CALL_HOOK = "1".equals(System.getenv( + "HOSTTEST_SKIP_METHOD_CALL_HOOK")); + /** If true, we won't print method call log. */ - private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv( - "HOSTTEST_SKIP_METHOD_LOG")); + private static final boolean SKIP_METHOD_LOG = + "1".equals(System.getenv("HOSTTEST_SKIP_METHOD_LOG")) + || "1".equals(System.getenv("RAVENWOOD_NO_METHOD_LOG")); /** If true, we won't print class load log. */ private static final boolean SKIP_CLASS_LOG = "1".equals(System.getenv( @@ -65,6 +71,9 @@ public class HostTestUtils { + "consider using Mockito; more details at go/ravenwood-docs"); } + private static final Class<?>[] sMethodHookArgTypes = + { Class.class, String.class, String.class}; + /** * Trampoline method for method-call-hook. */ @@ -74,16 +83,22 @@ public class HostTestUtils { String methodDescriptor, String callbackMethod ) { - callStaticMethodByName(callbackMethod, "method call hook", methodClass, - methodName, methodDescriptor); + if (SKIP_METHOD_CALL_HOOK) { + return; + } + callStaticMethodByName(callbackMethod, "method call hook", sMethodHookArgTypes, + methodClass, methodName, methodDescriptor); } /** + * Simple implementation of method call hook, which just prints the information of the + * method. This is just for basic testing. We don't use it in Ravenwood, because this would + * be way too noisy as it prints every single method, even trivial ones. (iterator methods, + * etc..) + * * I can be used as * {@code --default-method-call-hook * com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall}. - * - * It logs every single methods called. */ public static void logMethodCall( Class<?> methodClass, @@ -97,6 +112,8 @@ public class HostTestUtils { + methodName + methodDescriptor); } + private static final Class<?>[] sClassLoadHookArgTypes = { Class.class }; + /** * Called when any top level class (not nested classes) in the impl jar is loaded. * @@ -111,11 +128,12 @@ public class HostTestUtils { logPrintStream.println("! Class loaded: " + loadedClass.getCanonicalName() + " calling hook " + callbackMethod); - callStaticMethodByName(callbackMethod, "class load hook", loadedClass); + callStaticMethodByName( + callbackMethod, "class load hook", sClassLoadHookArgTypes, loadedClass); } private static void callStaticMethodByName(String classAndMethodName, - String description, Object... args) { + String description, Class<?>[] argTypes, Object... args) { // Forward the call to callbackMethod. final int lastPeriod = classAndMethodName.lastIndexOf("."); @@ -145,19 +163,14 @@ public class HostTestUtils { className)); } - Class<?>[] argTypes = new Class[args.length]; - for (int i = 0; i < args.length; i++) { - argTypes[i] = args[i].getClass(); - } - Method method = null; try { method = clazz.getMethod(methodName, argTypes); } catch (Exception e) { throw new HostTestException(String.format( "Unable to find %s: class %s doesn't have method %s" - + " (method must take exactly one parameter of type Class," - + " and public static)", + + " Method must be public static, and arg types must be: " + + Arrays.toString(argTypes), description, className, methodName), e); } if (!(Modifier.isPublic(method.getModifiers()) diff --git a/ravenwood/tools/hoststubgen/framework-policy-override.txt b/ravenwood/tools/hoststubgen/hoststubgen-test-policy-override.txt index af3789e270a4..000771a7022e 100644 --- a/ravenwood/tools/hoststubgen/framework-policy-override.txt +++ b/ravenwood/tools/hoststubgen/hoststubgen-test-policy-override.txt @@ -1,30 +1,7 @@ -# -------------------------------------------------------------------------------------------------- -# This file contains rules to process `framework-all.jar` to generate the host side test "stub" and -# "impl" jars, without using Java annotations. -# -# Useful when: -# - The class is auto-generated and annotations can't be added. -# (We need to figure out what to do on auto-generated classes.) -# - Want to quickly change filter rules without having to rebuild framework.jar. -# -# Using this file, one can control the visibility of APIs on a per-class, per-field and per-method -# basis, but in most cases, per-class directives would be sufficient. That is: -# -# - To put the entire class, including its members and nested classes, in the "stub" jar, -# so that the test / target code can use the API, use `stubclass`. -# -# class package.class stubclass -# -# - To put the entire class, including its members and nested classes, in the "impl" jar, -# but not in the "stub" jar, use `keepclass`. Use this when you don't want to expose an API to -# tests/target directly, but it's still needed at runtime, because it's used by other "stub" APIs -# directly or indirectly. -# -# class package.class keepclass -# -# All other classes will be removed from both the stub jar and impl jar. -# -# -------------------------------------------------------------------------------------------------- +# ************************************************************************************************* +# This file contains "policies" for HostStubGen used by its automated tests. +# For the "real" Ravenwood policies, see the frameworks/base/ravenwood/texts/ directory. +# ************************************************************************************************* # -------------------------------------------------------------------------------------------------- # Directions on auto-generated classes, where we can't use Java annotations (yet). diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt index 985947575a86..83a7069bb308 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt @@ -29,7 +29,7 @@ import com.android.hoststubgen.filters.OutputFilter import com.android.hoststubgen.filters.SanitizationFilter import com.android.hoststubgen.filters.TextFileFilterPolicyBuilder import com.android.hoststubgen.filters.printAsTextPolicy -import com.android.hoststubgen.utils.ClassFilter +import com.android.hoststubgen.utils.ClassPredicate import com.android.hoststubgen.visitors.BaseAdapter import com.android.hoststubgen.visitors.PackageRedirectRemapper import java.io.BufferedInputStream @@ -145,6 +145,7 @@ class HostStubGen(val options: HostStubGenOptions) { // Inject default hooks from options. filter = DefaultHookInjectingFilter( + allClasses, options.defaultClassLoadHook.get, options.defaultMethodCallHook.get, filter @@ -152,9 +153,9 @@ class HostStubGen(val options: HostStubGenOptions) { val annotationAllowedClassesFilter = options.annotationAllowedClassesFile.get.let { file -> if (file == null) { - ClassFilter.newNullFilter(true) // Allow all classes + ClassPredicate.newConstantPredicate(true) // Allow all classes } else { - ClassFilter.loadFromFile(file, false) + ClassPredicate.loadFromFile(file, false) } } diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt index 36adf0626415..9b5d60237db0 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt @@ -31,7 +31,7 @@ import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.asm.toHumanReadableMethodName import com.android.hoststubgen.asm.toJvmClassName import com.android.hoststubgen.log -import com.android.hoststubgen.utils.ClassFilter +import com.android.hoststubgen.utils.ClassPredicate import org.objectweb.asm.tree.AnnotationNode import org.objectweb.asm.tree.ClassNode @@ -54,7 +54,7 @@ class AnnotationBasedFilter( redirectionClassAnnotations_: Set<String>, classLoadHookAnnotations_: Set<String>, keepStaticInitializerAnnotations_: Set<String>, - private val annotationAllowedClassesFilter: ClassFilter, + private val annotationAllowedClassesFilter: ClassPredicate, fallback: OutputFilter, ) : DelegatingFilter(fallback) { private val keepAnnotations = convertToInternalNames(keepAnnotations_) diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt index d771003a955d..aaf49c154a17 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt @@ -16,8 +16,11 @@ package com.android.hoststubgen.filters import com.android.hoststubgen.addLists +import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.isAnnotation class DefaultHookInjectingFilter( + val classes: ClassNodes, defaultClassLoadHook: String?, defaultMethodCallHook: String?, fallback: OutputFilter @@ -36,8 +39,30 @@ class DefaultHookInjectingFilter( private val defaultClassLoadHookAsList: List<String> = toSingleList(defaultClassLoadHook) private val defaultMethodCallHookAsList: List<String> = toSingleList(defaultMethodCallHook) + private fun shouldInject(className: String): Boolean { + // Let's not inject default hooks to annotation classes or inner classes of an annotation + // class, because these methods could be called at the class load time, which + // is very confusing, and usually not useful. + + val cn = classes.findClass(className) ?: return false + if (cn.isAnnotation()) { + return false + } + cn.nestHostClass?.let { nestHostClass -> + val nestHost = classes.findClass(nestHostClass) ?: return false + if (nestHost.isAnnotation()) { + return false + } + } + return true + } + override fun getClassLoadHooks(className: String): List<String> { - return addLists(super.getClassLoadHooks(className), defaultClassLoadHookAsList) + val s = super.getClassLoadHooks(className) + if (!shouldInject(className)) { + return s + } + return addLists(s, defaultClassLoadHookAsList) } override fun getMethodCallHooks( @@ -45,9 +70,23 @@ class DefaultHookInjectingFilter( methodName: String, descriptor: String ): List<String> { - return addLists( - super.getMethodCallHooks(className, methodName, descriptor), - defaultMethodCallHookAsList, - ) + val s = super.getMethodCallHooks(className, methodName, descriptor) + if (!shouldInject(className)) { + return s + } + // Don't hook Object methods. + if (methodName == "finalize" && descriptor == "()V") { + return s + } + if (methodName == "toString" && descriptor == "()Ljava/lang/String;") { + return s + } + if (methodName == "equals" && descriptor == "(Ljava/lang/Object;)Z") { + return s + } + if (methodName == "hashCode" && descriptor == "()I") { + return s + } + return addLists(s, defaultMethodCallHookAsList) } -}
\ No newline at end of file +} diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassPredicate.kt index d6aa7617fd59..810dd71732c8 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassFilter.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassPredicate.kt @@ -24,7 +24,7 @@ import java.io.File /** * General purpose filter for class names. */ -class ClassFilter private constructor( +class ClassPredicate private constructor( private val defaultResult: Boolean, ) { private enum class MatchType { @@ -81,14 +81,14 @@ class ClassFilter private constructor( companion object { /** - * Return a filter that alawys returns true or false. + * Return a filter that always returns true or false. */ - fun newNullFilter(defaultResult: Boolean): ClassFilter { - return ClassFilter(defaultResult) + fun newConstantPredicate(defaultResult: Boolean): ClassPredicate { + return ClassPredicate(defaultResult) } /** Build a filter from a file. */ - fun loadFromFile(filename: String, defaultResult: Boolean): ClassFilter { + fun loadFromFile(filename: String, defaultResult: Boolean): ClassPredicate { return buildFromString(File(filename).readText(), defaultResult, filename) } @@ -97,8 +97,8 @@ class ClassFilter private constructor( filterString: String, defaultResult: Boolean, filenameForErrorMessage: String - ): ClassFilter { - val ret = ClassFilter(defaultResult) + ): ClassPredicate { + val ret = ClassPredicate(defaultResult) var lineNo = 0 filterString.split('\n').forEach { s -> diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt index 49769e648bbf..fb225ff1aa21 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output.RELEASE_TARGET_JAVA_21/13-hoststubgen-test-tiny-framework-host-ext-dump.txt @@ -6,17 +6,9 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 2, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestClassLoadHook - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return - + interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -44,16 +36,9 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang. flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestKeep super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestKeep - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestKeep.java" RuntimeVisibleAnnotations: @@ -75,16 +60,9 @@ public interface android.hosttest.annotation.HostSideTestRedirect extends java.l flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestRedirect super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestRedirect - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestRedirect.java" RuntimeVisibleAnnotations: @@ -106,17 +84,9 @@ public interface android.hosttest.annotation.HostSideTestRedirectionClass extend flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 2, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestRedirectionClass - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return - + interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -144,16 +114,9 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestRemove super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestRemove - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestRemove.java" RuntimeVisibleAnnotations: @@ -175,16 +138,9 @@ public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep e flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestStaticInitializerKeep - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestStaticInitializerKeep.java" RuntimeVisibleAnnotations: @@ -206,17 +162,9 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestSubstitute super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 2, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestSubstitute - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return - + interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String suffix(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -244,16 +192,9 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestThrow super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestThrow - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestThrow.java" RuntimeVisibleAnnotations: @@ -275,16 +216,9 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassKeep - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestWholeClassKeep.java" RuntimeVisibleAnnotations: diff --git a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt index 0f8af92dc486..e4b9db2ed6d8 100644 --- a/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt +++ b/ravenwood/tools/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-dump.txt @@ -6,17 +6,9 @@ public interface android.hosttest.annotation.HostSideTestClassLoadHook extends j flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestClassLoadHook super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 2, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestClassLoadHook - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return - + interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -44,16 +36,9 @@ public interface android.hosttest.annotation.HostSideTestKeep extends java.lang. flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestKeep super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestKeep - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestKeep.java" RuntimeVisibleAnnotations: @@ -75,16 +60,9 @@ public interface android.hosttest.annotation.HostSideTestRedirect extends java.l flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestRedirect super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestRedirect - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestRedirect.java" RuntimeVisibleAnnotations: @@ -106,17 +84,9 @@ public interface android.hosttest.annotation.HostSideTestRedirectionClass extend flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestRedirectionClass super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 2, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestRedirectionClass - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return - + interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String value(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -144,16 +114,9 @@ public interface android.hosttest.annotation.HostSideTestRemove extends java.lan flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestRemove super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestRemove - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestRemove.java" RuntimeVisibleAnnotations: @@ -175,16 +138,9 @@ public interface android.hosttest.annotation.HostSideTestStaticInitializerKeep e flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestStaticInitializerKeep super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestStaticInitializerKeep - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestStaticInitializerKeep.java" RuntimeVisibleAnnotations: @@ -206,17 +162,9 @@ public interface android.hosttest.annotation.HostSideTestSubstitute extends java flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestSubstitute super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 2, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestSubstitute - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return - + interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ public abstract java.lang.String suffix(); descriptor: ()Ljava/lang/String; flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT @@ -244,16 +192,9 @@ public interface android.hosttest.annotation.HostSideTestThrow extends java.lang flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestThrow super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestThrow - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestThrow.java" RuntimeVisibleAnnotations: @@ -275,16 +216,9 @@ public interface android.hosttest.annotation.HostSideTestWholeClassKeep extends flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION this_class: #x // android/hosttest/annotation/HostSideTestWholeClassKeep super_class: #x // java/lang/Object - interfaces: 1, fields: 0, methods: 1, attributes: 2 - private static {}; - descriptor: ()V - flags: (0x000a) ACC_PRIVATE, ACC_STATIC - Code: - stack=2, locals=0, args_size=0 - x: ldc #x // class android/hosttest/annotation/HostSideTestWholeClassKeep - x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded - x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V - x: return + interfaces: 1, fields: 0, methods: 0, attributes: 2 +Constant pool: +{ } SourceFile: "HostSideTestWholeClassKeep.java" RuntimeVisibleAnnotations: @@ -307,6 +241,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub$Pro this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 4 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -377,6 +313,8 @@ public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 4 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -447,6 +385,8 @@ public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl this_class: #x // com/android/hoststubgen/test/tinyframework/IPretendingAidl super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 4 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -476,6 +416,8 @@ public class com.android.hoststubgen.test.tinyframework.R$Nested this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 4 +Constant pool: +{ public static int[] ARRAY; descriptor: [I flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -546,6 +488,8 @@ public class com.android.hoststubgen.test.tinyframework.R this_class: #x // com/android/hoststubgen/test/tinyframework/R super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 4 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -594,6 +538,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkAnnotations this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkAnnotations super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 7, attributes: 3 +Constant pool: +{ public int keep; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -785,6 +731,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassLoadHo this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassLoadHook super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 3, attributes: 3 +Constant pool: +{ public static final java.util.Set<java.lang.Class<?>> sLoadedClasses; descriptor: Ljava/util/Set; flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL @@ -880,6 +828,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWideAn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWideAnnotations super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 5, attributes: 3 +Constant pool: +{ public int keep; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -1010,6 +960,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerDefault super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 0, attributes: 3 +Constant pool: +{ public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -1047,6 +999,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkClassWithIn this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkClassWithInitializerStub super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 1, attributes: 3 +Constant pool: +{ public static boolean sInitialized; descriptor: Z flags: (0x0009) ACC_PUBLIC, ACC_STATIC @@ -1117,6 +1071,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumC this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex super_class: #x // java/lang/Enum interfaces: 0, fields: 6, methods: 7, attributes: 4 +Constant pool: +{ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumComplex RED; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumComplex; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM @@ -1400,6 +1356,8 @@ public final class com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumS this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple super_class: #x // java/lang/Enum interfaces: 0, fields: 3, methods: 5, attributes: 4 +Constant pool: +{ public static final com.android.hoststubgen.test.tinyframework.TinyFrameworkEnumSimple CAT; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkEnumSimple; flags: (0x4019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM @@ -1576,6 +1534,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkExceptionTe this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkExceptionTester super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 3 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -1659,6 +1619,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkForTextPoli this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 15, attributes: 2 +Constant pool: +{ public int stub; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -1971,6 +1933,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas$Nes this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas$Nested super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 8, attributes: 6 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -2201,6 +2165,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkLambdas this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkLambdas super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 8, attributes: 6 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -2432,6 +2398,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace$ReplaceTo super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 4, attributes: 4 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -2526,6 +2494,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkMethodCallR this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkMethodCallReplace super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 5, attributes: 6 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -2665,6 +2635,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 15, attributes: 3 +Constant pool: +{ int value; descriptor: I flags: (0x0000) @@ -2998,6 +2970,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNative_host this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNative_host super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 8, attributes: 3 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -3173,6 +3147,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$1 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$1 super_class: #x // java/lang/Object interfaces: 1, fields: 1, methods: 4, attributes: 6 +Constant pool: +{ final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC @@ -3278,6 +3254,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$2 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 4, attributes: 6 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -3369,6 +3347,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$3 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$3 super_class: #x // java/lang/Object interfaces: 1, fields: 1, methods: 4, attributes: 6 +Constant pool: +{ final com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses this$0; descriptor: Lcom/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses; flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC @@ -3474,6 +3454,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$4 ex this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$4 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 4, attributes: 6 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -3565,6 +3547,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 4 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -3623,6 +3607,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$InnerClass super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 2, attributes: 4 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -3694,6 +3680,8 @@ class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses$Stat this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$1 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 4, attributes: 6 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -3786,6 +3774,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass$Double$NestedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 2, attributes: 4 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -3844,6 +3834,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$StaticNestedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 3, attributes: 4 +Constant pool: +{ public int value; descriptor: I flags: (0x0001) ACC_PUBLIC @@ -3923,6 +3915,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$SubClass super_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses$BaseClass interfaces: 0, fields: 0, methods: 2, attributes: 4 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -3973,6 +3967,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClass this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkNestedClasses super_class: #x // java/lang/Object interfaces: 0, fields: 2, methods: 4, attributes: 5 +Constant pool: +{ public final java.util.function.Supplier<java.lang.Integer> mSupplier; descriptor: Ljava/util/function/Supplier; flags: (0x0011) ACC_PUBLIC, ACC_FINAL @@ -4121,6 +4117,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkPackageRedi this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkPackageRedirect super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 3 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4192,6 +4190,8 @@ public class com.android.hoststubgen.test.tinyframework.TinyFrameworkRenamedClas this_class: #x // com/android/hoststubgen/test/tinyframework/TinyFrameworkRenamedClassCaller super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 3 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4263,6 +4263,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.A this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4286,6 +4288,8 @@ public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A this_class: #x // com/android/hoststubgen/test/tinyframework/packagetest/sub/A super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4309,6 +4313,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C1 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4332,6 +4338,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C2 extends this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4355,6 +4363,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.C3 extends this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4378,6 +4388,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CA super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4401,6 +4413,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.CB this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/CB super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4424,6 +4438,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C1 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C1 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C1 interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4447,6 +4463,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C2 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C2 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C2 interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4470,6 +4488,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_C3 ex this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_C3 super_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/C3 interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4493,6 +4513,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4516,6 +4538,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I1_IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I1_IA super_class: #x // java/lang/Object interfaces: 2, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4539,6 +4563,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I2 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4562,6 +4588,8 @@ public class com.android.hoststubgen.test.tinyframework.subclasstest.Class_I3 im this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/Class_I3 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4585,6 +4613,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I1 this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I1 super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4608,6 +4638,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I2 exte this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I2 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4631,6 +4663,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.I3 exte this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/I3 super_class: #x // java/lang/Object interfaces: 1, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4654,6 +4688,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IA this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IA super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4677,6 +4713,8 @@ public interface com.android.hoststubgen.test.tinyframework.subclasstest.IB this_class: #x // com/android/hoststubgen/test/tinyframework/subclasstest/IB super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 1, attributes: 2 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4700,6 +4738,8 @@ public class com.supported.UnsupportedClass this_class: #x // com/supported/UnsupportedClass super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 3, attributes: 3 +Constant pool: +{ private final int mValue; descriptor: I flags: (0x0012) ACC_PRIVATE, ACC_FINAL @@ -4779,6 +4819,8 @@ public class com.unsupported.UnsupportedClass this_class: #x // com/unsupported/UnsupportedClass super_class: #x // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 3 +Constant pool: +{ private static {}; descriptor: ()V flags: (0x000a) ACC_PRIVATE, ACC_STATIC @@ -4854,6 +4896,8 @@ public class rename_prefix.com.android.hoststubgen.test.tinyframework.TinyFramew this_class: #x // rename_prefix/com/android/hoststubgen/test/tinyframework/TinyFrameworkToBeRenamed super_class: #x // java/lang/Object interfaces: 0, fields: 1, methods: 3, attributes: 3 +Constant pool: +{ private final int mValue; descriptor: I flags: (0x0012) ACC_PRIVATE, ACC_FINAL diff --git a/ravenwood/tools/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt b/ravenwood/tools/hoststubgen/test/com/android/hoststubgen/utils/ClassPredicateTest.kt index d4e75d43a54a..5a877e661484 100644 --- a/ravenwood/tools/hoststubgen/test/com/android/hoststubgen/utils/ClassFilterTest.kt +++ b/ravenwood/tools/hoststubgen/test/com/android/hoststubgen/utils/ClassPredicateTest.kt @@ -20,22 +20,22 @@ import com.google.common.truth.Truth.assertThat import org.junit.Assert.fail import org.junit.Test -class ClassFilterTest { +class ClassPredicateTest { @Test fun testDefaultTrue() { - val f = ClassFilter.newNullFilter(true) + val f = ClassPredicate.newConstantPredicate(true) assertThat(f.matches("a/b/c")).isEqualTo(true) } @Test fun testDefaultFalse() { - val f = ClassFilter.newNullFilter(false) + val f = ClassPredicate.newConstantPredicate(false) assertThat(f.matches("a/b/c")).isEqualTo(false) } @Test fun testComplex1() { - val f = ClassFilter.buildFromString(""" + val f = ClassPredicate.buildFromString(""" # ** this is a comment ** a.b.c # allow !a.b.d # disallow @@ -57,7 +57,7 @@ class ClassFilterTest { @Test fun testComplex2() { - val f = ClassFilter.buildFromString(""" + val f = ClassPredicate.buildFromString(""" a.b.c # allow !a.* # disallow everything else in package "a". !d.e.f # disallow d.e.f. @@ -75,7 +75,7 @@ class ClassFilterTest { @Test fun testNestedClass() { - val f = ClassFilter.buildFromString("a.b.c\nm.n.o\$p\n", false, "X") + val f = ClassPredicate.buildFromString("a.b.c\nm.n.o\$p\n", false, "X") assertThat(f.matches("a/b/c")).isEqualTo(true) assertThat(f.matches("a/b/c\$d")).isEqualTo(true) assertThat(f.matches("a/b/c\$d\$e")).isEqualTo(true) @@ -88,7 +88,7 @@ class ClassFilterTest { @Test fun testBadFilter1() { try { - ClassFilter.buildFromString(""" + ClassPredicate.buildFromString(""" a* """.trimIndent(), true, "FILENAME") fail("ParseException didn't happen") @@ -101,7 +101,7 @@ class ClassFilterTest { @Test fun testSuffix() { - val f = ClassFilter.buildFromString(""" + val f = ClassPredicate.buildFromString(""" *.Abc # allow !* # Disallow by default """.trimIndent(), true, "X") diff --git a/ravenwood/tools/ravenhelper/Android.bp b/ravenwood/tools/ravenhelper/Android.bp index a7ee4684506e..3da6dd824c37 100644 --- a/ravenwood/tools/ravenhelper/Android.bp +++ b/ravenwood/tools/ravenhelper/Android.bp @@ -24,3 +24,14 @@ java_binary_host { ], visibility: ["//visibility:public"], } + +java_test_host { + name: "ravenhelpertest", + srcs: ["test/**/*.kt"], + static_libs: [ + "ravenhelper", + "truth", + ], + test_suites: ["general-tests"], + visibility: ["//visibility:private"], +} diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt index 3657a9077577..b6089eaff1ed 100644 --- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt +++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt @@ -24,7 +24,7 @@ import com.android.hoststubgen.filters.SpecialClass import com.android.hoststubgen.filters.TextFileFilterPolicyParser import com.android.hoststubgen.filters.TextFilePolicyMethodReplaceFilter import com.android.hoststubgen.log -import com.android.hoststubgen.utils.ClassFilter +import com.android.hoststubgen.utils.ClassPredicate import com.android.platform.test.ravenwood.ravenhelper.SubcommandHandler import com.android.platform.test.ravenwood.ravenhelper.psi.createUastEnvironment import com.android.platform.test.ravenwood.ravenhelper.sourcemap.AllClassInfo @@ -66,11 +66,11 @@ private class TextPolicyToAnnotationConverter( val annotations: Annotations, val dumpOperations: Boolean, ) { - private val annotationAllowedClasses: ClassFilter = annotationAllowedClassesFile.let { file -> + private val annotationAllowedClasses: ClassPredicate = annotationAllowedClassesFile.let { file -> if (file == null) { - ClassFilter.newNullFilter(true) // Allow all classes + ClassPredicate.newConstantPredicate(true) // Allow all classes } else { - ClassFilter.loadFromFile(file, false) + ClassPredicate.loadFromFile(file, false) } } diff --git a/ravenwood/tools/ravenhelper/test/com/android/platform/test/ravenwood/ravenhelper/RavenhelperTest.kt b/ravenwood/tools/ravenhelper/test/com/android/platform/test/ravenwood/ravenhelper/RavenhelperTest.kt new file mode 100644 index 000000000000..203fab1544c9 --- /dev/null +++ b/ravenwood/tools/ravenhelper/test/com/android/platform/test/ravenwood/ravenhelper/RavenhelperTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.platform.test.ravenwood.ravenhelper + +import com.android.platform.test.ravenwood.ravenhelper.psi.createUastEnvironment +import org.junit.Test + +class RavenhelperTest { + @Test + fun testPsiInitialization() { + val env = createUastEnvironment() + env.dispose() + } +}
\ No newline at end of file diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig index bb0eacb5afa7..5e1fe8a60973 100644 --- a/services/accessibility/accessibility.aconfig +++ b/services/accessibility/accessibility.aconfig @@ -11,6 +11,16 @@ flag { } flag { + name: "allow_secure_screenshots" + namespace: "accessibility" + description: "Allow certain AccessibilityServices to take screenshots of FLAG_SECURE screens" + bug: "373705911" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "always_allow_observing_touch_events" namespace: "accessibility" description: "Always allows InputFilter observing SOURCE_TOUCHSCREEN events, even if touch exploration is enabled." diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 9ceca5d1dbfe..4b042489f3eb 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -86,11 +86,13 @@ import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.View; +import android.view.WindowManager; import android.view.accessibility.AccessibilityCache; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; +import android.view.accessibility.IWindowSurfaceInfoCallback; import android.view.inputmethod.EditorInfo; import android.window.ScreenCapture; import android.window.ScreenCapture.ScreenshotHardwareBuffer; @@ -343,6 +345,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ SurfaceControl sc, IAccessibilityInteractionConnectionCallback callback); + int performScreenCapture(ScreenCapture.LayerCaptureArgs captureArgs, + ScreenCapture.ScreenCaptureListener captureListener); } public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, @@ -1456,7 +1460,45 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_WINDOW, interactionId); return; } - connection.getRemote().takeScreenshotOfWindow(interactionId, listener, callback); + if (Flags.allowSecureScreenshots()) { + IWindowSurfaceInfoCallback infoCallback = new IWindowSurfaceInfoCallback.Stub() { + @Override + public void provideWindowSurfaceInfo(int windowFlags, int processUid, + SurfaceControl surfaceControl) { + final boolean canCaptureSecureLayers = canCaptureSecureLayers(); + if (!canCaptureSecureLayers + && (windowFlags & WindowManager.LayoutParams.FLAG_SECURE) != 0) { + try { + callback.sendTakeScreenshotOfWindowError( + AccessibilityService.ERROR_TAKE_SCREENSHOT_SECURE_WINDOW, + interactionId); + } catch (RemoteException e) { + // ignore - the other side will time out + } + return; + } + + final ScreenCapture.LayerCaptureArgs captureArgs = + new ScreenCapture.LayerCaptureArgs.Builder(surfaceControl) + .setChildrenOnly(false) + .setUid(processUid) + .setCaptureSecureLayers(canCaptureSecureLayers) + .build(); + if (mSystemSupport.performScreenCapture(captureArgs, listener) != 0) { + try { + callback.sendTakeScreenshotOfWindowError( + AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR, + interactionId); + } catch (RemoteException e) { + // ignore - the other side will time out + } + } + } + }; + connection.getRemote().getWindowSurfaceInfo(infoCallback); + } else { + connection.getRemote().takeScreenshotOfWindow(interactionId, listener, callback); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -1523,7 +1565,14 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } } ); - mWindowManagerService.captureDisplay(displayId, null, screenCaptureListener); + if (Flags.allowSecureScreenshots()) { + mWindowManagerService.captureDisplay(displayId, + new ScreenCapture.CaptureArgs.Builder<>() + .setCaptureSecureLayers(canCaptureSecureLayers()).build(), + screenCaptureListener); + } else { + mWindowManagerService.captureDisplay(displayId, null, screenCaptureListener); + } } catch (Exception e) { sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback); @@ -1564,6 +1613,13 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ }, null).recycleOnUse()); } + private boolean canCaptureSecureLayers() { + return Flags.allowSecureScreenshots() + && mAccessibilityServiceInfo.isAccessibilityTool() + && mAccessibilityServiceInfo.getResolveInfo().serviceInfo + .applicationInfo.isSystemApp(); + } + @Override @PermissionManuallyEnforced public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index e422fef6c22c..9b5f22afb81d 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -134,7 +134,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo */ static final int FLAG_SERVICE_HANDLES_DOUBLE_TAP = 0x00000080; -/** + /** * Flag for enabling multi-finger gestures. * * @see #setUserAndEnabledFeatures(int, int) @@ -190,8 +190,6 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo private final AccessibilityManagerService mAms; - private final InputManager mInputManager; - private final SparseArray<EventStreamTransformation> mEventHandler; private final SparseArray<TouchExplorer> mTouchExplorer = new SparseArray<>(0); @@ -294,7 +292,6 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo mContext = context; mAms = service; mPm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - mInputManager = context.getSystemService(InputManager.class); mEventHandler = eventHandler; } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 67fdca446ba4..9eb8442be783 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -173,6 +173,7 @@ import android.view.accessibility.IAccessibilityManagerClient; import android.view.accessibility.IMagnificationConnection; import android.view.accessibility.IUserInitializationCompleteCallback; import android.view.inputmethod.EditorInfo; +import android.window.ScreenCapture; import com.android.internal.R; import com.android.internal.accessibility.AccessibilityShortcutController; @@ -6725,6 +6726,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub callback)); } + @Override + public int performScreenCapture(ScreenCapture.LayerCaptureArgs captureArgs, + ScreenCapture.ScreenCaptureListener captureListener) { + return ScreenCapture.captureLayers(captureArgs, captureListener); + } + @VisibleForTesting int getShortcutTypeForGenericShortcutCalls(int userId) { int navigationMode = Settings.Secure.getIntForUser( diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java index 4fa0d506f09e..aa82df493f84 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickController.java @@ -101,8 +101,15 @@ public class AutoclickController extends BaseEventStreamTransformation { } @Override - public void toggleAutoclickPause() { - // TODO(b/388872274): allows users to pause the autoclick. + public void toggleAutoclickPause(boolean paused) { + if (paused) { + if (mClickScheduler != null) { + mClickScheduler.cancel(); + } + if (mAutoclickIndicatorScheduler != null) { + mAutoclickIndicatorScheduler.cancel(); + } + } } }; @@ -133,7 +140,9 @@ public class AutoclickController extends BaseEventStreamTransformation { mAutoclickIndicatorScheduler); } - handleMouseMotion(event, policyFlags); + if (!isPaused()) { + handleMouseMotion(event, policyFlags); + } } else if (mClickScheduler != null) { mClickScheduler.cancel(); } @@ -216,6 +225,11 @@ public class AutoclickController extends BaseEventStreamTransformation { } } + private boolean isPaused() { + // TODO (b/397460424): Unpause when hovering over panel. + return Flags.enableAutoclickIndicator() && mAutoclickTypePanel.isPaused(); + } + /** * Observes autoclick setting values, and updates ClickScheduler delay and indicator size * whenever the setting value changes. diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java index 614b2285d6e0..ba3e3d14b9c6 100644 --- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java +++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java @@ -46,6 +46,11 @@ public class AutoclickTypePanel { public static final int AUTOCLICK_TYPE_DRAG = 3; public static final int AUTOCLICK_TYPE_SCROLL = 4; + public static final int CORNER_BOTTOM_RIGHT = 0; + public static final int CORNER_BOTTOM_LEFT = 1; + public static final int CORNER_TOP_LEFT = 2; + public static final int CORNER_TOP_RIGHT = 3; + // Types of click the AutoclickTypePanel supports. @IntDef({ AUTOCLICK_TYPE_LEFT_CLICK, @@ -56,14 +61,38 @@ public class AutoclickTypePanel { }) public @interface AutoclickType {} + @IntDef({ + CORNER_BOTTOM_RIGHT, + CORNER_BOTTOM_LEFT, + CORNER_TOP_LEFT, + CORNER_TOP_RIGHT + }) + public @interface Corner {} + + private static final @Corner int[] CORNER_ROTATION_ORDER = { + CORNER_BOTTOM_RIGHT, + CORNER_BOTTOM_LEFT, + CORNER_TOP_LEFT, + CORNER_TOP_RIGHT + }; + // An interface exposed to {@link AutoclickController) to handle different actions on the panel, // including changing autoclick type, pausing/resuming autoclick. public interface ClickPanelControllerInterface { - // Allows users to change a different autoclick type. + /** + * Allows users to change a different autoclick type. + * + * @param clickType The new autoclick type to use. Should be one of the values defined in + * {@link AutoclickType}. + */ void handleAutoclickTypeChange(@AutoclickType int clickType); - // Allows users to pause/resume the autoclick. - void toggleAutoclickPause(); + /** + * Allows users to pause or resume autoclick. + * + * @param paused {@code true} to pause autoclick, {@code false} to resume. + */ + void toggleAutoclickPause(boolean paused); } private final Context mContext; @@ -77,14 +106,26 @@ public class AutoclickTypePanel { // Whether the panel is expanded or not. private boolean mExpanded = false; + // Whether autoclick is paused. + private boolean mPaused = false; + // Tracks the current corner position of the panel using an index into CORNER_ROTATION_ORDER + // array. This allows the panel to cycle through screen corners in a defined sequence when + // repositioned. + private int mCurrentCornerIndex = 0; + private final LinearLayout mLeftClickButton; private final LinearLayout mRightClickButton; private final LinearLayout mDoubleClickButton; private final LinearLayout mDragButton; private final LinearLayout mScrollButton; + private final LinearLayout mPauseButton; + private final LinearLayout mPositionButton; private LinearLayout mSelectedButton; + private final Drawable mPauseButtonDrawable; + private final Drawable mResumeButtonDrawable; + public AutoclickTypePanel( Context context, WindowManager windowManager, @@ -93,6 +134,11 @@ public class AutoclickTypePanel { mWindowManager = windowManager; mClickPanelController = clickPanelController; + mPauseButtonDrawable = mContext.getDrawable( + R.drawable.accessibility_autoclick_pause); + mResumeButtonDrawable = mContext.getDrawable( + R.drawable.accessibility_autoclick_resume); + mContentView = LayoutInflater.from(context) .inflate(R.layout.accessibility_autoclick_type_panel, null); @@ -104,6 +150,8 @@ public class AutoclickTypePanel { mContentView.findViewById(R.id.accessibility_autoclick_double_click_layout); mScrollButton = mContentView.findViewById(R.id.accessibility_autoclick_scroll_layout); mDragButton = mContentView.findViewById(R.id.accessibility_autoclick_drag_layout); + mPauseButton = mContentView.findViewById(R.id.accessibility_autoclick_pause_layout); + mPositionButton = mContentView.findViewById(R.id.accessibility_autoclick_position_layout); initializeButtonState(); } @@ -115,11 +163,8 @@ public class AutoclickTypePanel { v -> togglePanelExpansion(AUTOCLICK_TYPE_DOUBLE_CLICK)); mScrollButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_SCROLL)); mDragButton.setOnClickListener(v -> togglePanelExpansion(AUTOCLICK_TYPE_DRAG)); - - // TODO(b/388872274): registers listener for pause button and allows users to pause/resume - // the autoclick. - // TODO(b/388847771): registers listener for position button and allows users to move the - // panel to a different position. + mPositionButton.setOnClickListener(v -> moveToNextCorner()); + mPauseButton.setOnClickListener(v -> togglePause()); // Initializes panel as collapsed state and only displays the left click button. hideAllClickTypeButtons(); @@ -175,6 +220,10 @@ public class AutoclickTypePanel { mWindowManager.removeView(mContentView); } + public boolean isPaused() { + return mPaused; + } + /** Toggles the panel expanded or collapsed state. */ private void togglePanelExpansion(@AutoclickType int clickType) { final LinearLayout button = getButtonFromClickType(clickType); @@ -196,6 +245,18 @@ public class AutoclickTypePanel { mExpanded = !mExpanded; } + private void togglePause() { + mPaused = !mPaused; + mClickPanelController.toggleAutoclickPause(mPaused); + + ImageButton imageButton = (ImageButton) mPauseButton.getChildAt(/* index= */ 0); + if (mPaused) { + imageButton.setImageDrawable(mResumeButtonDrawable); + } else { + imageButton.setImageDrawable(mPauseButtonDrawable); + } + } + /** Hide all buttons on the panel except pause and position buttons. */ private void hideAllClickTypeButtons() { mLeftClickButton.setVisibility(View.GONE); @@ -225,6 +286,46 @@ public class AutoclickTypePanel { }; } + /** Moves the panel to the next corner in clockwise direction. */ + private void moveToNextCorner() { + @Corner int nextCornerIndex = (mCurrentCornerIndex + 1) % CORNER_ROTATION_ORDER.length; + mCurrentCornerIndex = nextCornerIndex; + + // getLayoutParams() will update the panel position based on current corner. + WindowManager.LayoutParams params = getLayoutParams(); + mWindowManager.updateViewLayout(mContentView, params); + } + + private void setPanelPositionForCorner(WindowManager.LayoutParams params, @Corner int corner) { + // TODO(b/396402941): Replace hardcoded pixel values with proper dimension calculations, + // Current values are experimental and may not work correctly across different device + // resolutions and configurations. + switch (corner) { + case CORNER_BOTTOM_RIGHT: + params.gravity = Gravity.END | Gravity.BOTTOM; + params.x = 15; + params.y = 90; + break; + case CORNER_BOTTOM_LEFT: + params.gravity = Gravity.START | Gravity.BOTTOM; + params.x = 15; + params.y = 90; + break; + case CORNER_TOP_LEFT: + params.gravity = Gravity.START | Gravity.TOP; + params.x = 15; + params.y = 30; + break; + case CORNER_TOP_RIGHT: + params.gravity = Gravity.END | Gravity.TOP; + params.x = 15; + params.y = 30; + break; + default: + throw new IllegalArgumentException("Invalid corner: " + corner); + } + } + @VisibleForTesting boolean getExpansionStateForTesting() { return mExpanded; @@ -236,12 +337,19 @@ public class AutoclickTypePanel { return mContentView; } + @VisibleForTesting + @Corner + int getCurrentCornerIndexForTesting() { + return mCurrentCornerIndex; + } + /** * Retrieves the layout params for AutoclickIndicatorView, used when it's added to the Window * Manager. */ + @VisibleForTesting @NonNull - private WindowManager.LayoutParams getLayoutParams() { + WindowManager.LayoutParams getLayoutParams() { final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; @@ -254,11 +362,7 @@ public class AutoclickTypePanel { mContext.getString(R.string.accessibility_autoclick_type_settings_panel_title); layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; - // TODO(b/388847771): Compute position based on user interaction. - layoutParams.x = 15; - layoutParams.y = 90; - layoutParams.gravity = Gravity.END | Gravity.BOTTOM; - + setPanelPositionForCorner(layoutParams, mCurrentCornerIndex); return layoutParams; } } diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java index d0ee7af1bbfb..5191fb5f51cb 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java @@ -20,6 +20,8 @@ import static android.app.appfunctions.AppFunctionRuntimeMetadata.APP_FUNCTION_R import static android.app.appfunctions.AppFunctionRuntimeMetadata.APP_FUNCTION_RUNTIME_NAMESPACE; import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR; +import static com.android.server.appfunctions.CallerValidator.CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION; +import static com.android.server.appfunctions.CallerValidator.CAN_EXECUTE_APP_FUNCTIONS_DENIED; import android.annotation.NonNull; import android.annotation.Nullable; @@ -236,30 +238,42 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { requestInternal.getCallingPackage(), targetPackageName, requestInternal.getClientRequest().getFunctionIdentifier()) - .thenAccept( - canExecute -> { - if (!canExecute) { - throw new SecurityException( + .thenCompose( + canExecuteResult -> { + if (canExecuteResult == CAN_EXECUTE_APP_FUNCTIONS_DENIED) { + return AndroidFuture.failedFuture(new SecurityException( "Caller does not have permission to execute the" - + " appfunction"); + + " appfunction")); } + return isAppFunctionEnabled( + requestInternal + .getClientRequest() + .getFunctionIdentifier(), + requestInternal + .getClientRequest() + .getTargetPackageName(), + getAppSearchManagerAsUser( + requestInternal.getUserHandle()), + THREAD_POOL_EXECUTOR) + .thenApply( + isEnabled -> { + if (!isEnabled) { + throw new DisabledAppFunctionException( + "The app function is disabled"); + } + return canExecuteResult; + }); }) - .thenCompose( - isEnabled -> - isAppFunctionEnabled( - requestInternal.getClientRequest().getFunctionIdentifier(), - requestInternal.getClientRequest().getTargetPackageName(), - getAppSearchManagerAsUser(requestInternal.getUserHandle()), - THREAD_POOL_EXECUTOR)) .thenAccept( - isEnabled -> { - if (!isEnabled) { - throw new DisabledAppFunctionException( - "The app function is disabled"); + canExecuteResult -> { + int bindFlags = Context.BIND_AUTO_CREATE; + if (canExecuteResult + == CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION) { + // If the caller doesn't have the permission, do not use + // BIND_FOREGROUND_SERVICE to avoid it raising its process state by + // calling its own AppFunctions. + bindFlags |= Context.BIND_FOREGROUND_SERVICE; } - }) - .thenAccept( - unused -> { Intent serviceIntent = mInternalServiceHelper.resolveAppFunctionService( targetPackageName, targetUser); @@ -294,8 +308,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { targetUser, localCancelTransport, safeExecuteAppFunctionCallback, - /* bindFlags= */ Context.BIND_AUTO_CREATE - | Context.BIND_FOREGROUND_SERVICE, + bindFlags, callerBinder, callingUid); }) diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java index 98ef974b9443..c8038a4e56df 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java +++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidator.java @@ -17,12 +17,16 @@ package com.android.server.appfunctions; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.os.UserHandle; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AndroidFuture; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Interface for validating that the caller has the correct privilege to call an AppFunctionManager * API. @@ -70,7 +74,8 @@ public interface CallerValidator { * @param functionId The id of the app function to execute. * @return Whether the caller can execute the specified app function. */ - AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction( + @CanExecuteAppFunctionResult + AndroidFuture<Integer> verifyCallerCanExecuteAppFunction( int callingUid, int callingPid, @NonNull UserHandle targetUser, @@ -78,6 +83,31 @@ public interface CallerValidator { @NonNull String targetPackageName, @NonNull String functionId); + @IntDef( + prefix = {"CAN_EXECUTE_APP_FUNCTIONS_"}, + value = { + CAN_EXECUTE_APP_FUNCTIONS_DENIED, + CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_SAME_PACKAGE, + CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION, + }) + @Retention(RetentionPolicy.SOURCE) + @interface CanExecuteAppFunctionResult {} + + /** Callers are not allowed to execute app functions. */ + int CAN_EXECUTE_APP_FUNCTIONS_DENIED = 0; + + /** + * Callers can execute app functions because they are calling app functions from the same + * package. + */ + int CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_SAME_PACKAGE = 1; + + /** + * Callers can execute app functions because they have the necessary permission. + * This case also applies when a caller with the permission invokes their own app functions. + */ + int CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION = 2; + /** * Checks if the app function policy is allowed. * diff --git a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java index fe163d77c4fc..3f8b2e3316dc 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/CallerValidatorImpl.java @@ -16,24 +16,12 @@ package com.android.server.appfunctions; -import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_METADATA_DB; -import static android.app.appfunctions.AppFunctionStaticMetadataHelper.APP_FUNCTION_STATIC_NAMESPACE; -import static android.app.appfunctions.AppFunctionStaticMetadataHelper.getDocumentIdForAppFunction; - -import static com.android.server.appfunctions.AppFunctionExecutors.THREAD_POOL_EXECUTOR; - import android.Manifest; import android.annotation.BinderThread; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager.AppFunctionsPolicy; -import android.app.appsearch.AppSearchBatchResult; -import android.app.appsearch.AppSearchManager; -import android.app.appsearch.AppSearchManager.SearchContext; -import android.app.appsearch.AppSearchResult; -import android.app.appsearch.GenericDocument; -import android.app.appsearch.GetByDocumentIdRequest; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; @@ -84,64 +72,25 @@ class CallerValidatorImpl implements CallerValidator { @Override @RequiresPermission(Manifest.permission.EXECUTE_APP_FUNCTIONS) - public AndroidFuture<Boolean> verifyCallerCanExecuteAppFunction( + @CanExecuteAppFunctionResult + public AndroidFuture<Integer> verifyCallerCanExecuteAppFunction( int callingUid, int callingPid, @NonNull UserHandle targetUser, @NonNull String callerPackageName, @NonNull String targetPackageName, @NonNull String functionId) { - if (callerPackageName.equals(targetPackageName)) { - return AndroidFuture.completedFuture(true); - } - boolean hasExecutionPermission = mContext.checkPermission( - Manifest.permission.EXECUTE_APP_FUNCTIONS, callingPid, callingUid) + Manifest.permission.EXECUTE_APP_FUNCTIONS, callingPid, callingUid) == PackageManager.PERMISSION_GRANTED; - - if (!hasExecutionPermission) { - return AndroidFuture.completedFuture(false); + if (hasExecutionPermission) { + return AndroidFuture.completedFuture(CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_HAS_PERMISSION); } - - FutureAppSearchSession futureAppSearchSession = - new FutureAppSearchSessionImpl( - Objects.requireNonNull( - mContext.createContextAsUser(targetUser, 0) - .getSystemService(AppSearchManager.class)), - THREAD_POOL_EXECUTOR, - new SearchContext.Builder(APP_FUNCTION_STATIC_METADATA_DB).build()); - - String documentId = getDocumentIdForAppFunction(targetPackageName, functionId); - - return futureAppSearchSession - .getByDocumentId( - new GetByDocumentIdRequest.Builder(APP_FUNCTION_STATIC_NAMESPACE) - .addIds(documentId) - .build()) - .thenApply( - batchResult -> getGenericDocumentFromBatchResult(batchResult, documentId)) - // At this point, already checked the app has the permission. - .thenApply(document -> true) - .whenComplete( - (result, throwable) -> { - futureAppSearchSession.close(); - }); - } - - private static GenericDocument getGenericDocumentFromBatchResult( - AppSearchBatchResult<String, GenericDocument> result, String documentId) { - if (result.isSuccess()) { - return result.getSuccesses().get(documentId); + if (callerPackageName.equals(targetPackageName)) { + return AndroidFuture.completedFuture(CAN_EXECUTE_APP_FUNCTIONS_ALLOWED_SAME_PACKAGE); } - - AppSearchResult<GenericDocument> failedResult = result.getFailures().get(documentId); - throw new AppSearchException( - failedResult.getResultCode(), - "Unable to retrieve document with id: " - + documentId - + " due to " - + failedResult.getErrorMessage()); + return AndroidFuture.completedFuture(CAN_EXECUTE_APP_FUNCTIONS_DENIED); } @Override diff --git a/services/appwidget/Android.bp b/services/appwidget/Android.bp index 8119073fdf7f..9548afe398b1 100644 --- a/services/appwidget/Android.bp +++ b/services/appwidget/Android.bp @@ -17,6 +17,12 @@ filegroup { java_library_static { name: "services.appwidget", defaults: ["platform_service_defaults"], - srcs: [":services.appwidget-sources"], - libs: ["services.core"], + srcs: [ + ":services.appwidget-sources", + ":statslog-framework-java-gen", + ], + libs: [ + "androidx.annotation_annotation", + "services.core", + ], } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index e0f2939a2083..74a87ed92f52 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -50,6 +50,7 @@ import android.app.IApplicationThread; import android.app.IServiceConnection; import android.app.KeyguardManager; import android.app.PendingIntent; +import android.app.StatsManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener; import android.app.usage.Flags; @@ -124,6 +125,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.SparseLongArray; +import android.util.StatsEvent; import android.util.TypedValue; import android.util.Xml; import android.util.proto.ProtoInputStream; @@ -145,6 +147,7 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.IRemoteViewsFactory; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -433,6 +436,44 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); mAppOpsManagerInternal = LocalServices.getService(AppOpsManagerInternal.class); mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class); + registerPullCallbacks(); + } + + /** + * Register callbacks for pull atoms. + */ + private void registerPullCallbacks() { + final StatsManager manager = mContext.getSystemService(StatsManager.class); + manager.setPullAtomCallback(FrameworkStatsLog.WIDGET_MEMORY_STATS, + new StatsManager.PullAtomMetadata.Builder().build(), + new HandlerExecutor(mCallbackHandler), this::onPullAtom); + } + + /** + * Callback from StatsManager to log events indicated by the atomTag. This function will add + * the relevant events to the data list. + * + * @return PULL_SUCCESS if the pull was successful and events should be used, else PULL_SKIP. + */ + private int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) { + if (atomTag == FrameworkStatsLog.WIDGET_MEMORY_STATS) { + synchronized (mLock) { + for (Widget widget : mWidgets) { + if (widget.views != null) { + final int uid = widget.provider.id.uid; + final int appWidgetId = widget.appWidgetId; + final long bitmapMemoryUsage = + widget.views.estimateTotalBitmapMemoryUsage(); + StatsEvent event = FrameworkStatsLog.buildStatsEvent( + FrameworkStatsLog.WIDGET_MEMORY_STATS, uid, appWidgetId, + bitmapMemoryUsage); + data.add(event); + } + } + } + return StatsManager.PULL_SUCCESS; + } + return StatsManager.PULL_SKIP; } /** diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index 05301fdd8385..4f56483f487e 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -31,6 +31,8 @@ import static android.os.UserHandle.getCallingUserId; import static com.android.internal.util.CollectionUtils.any; import static com.android.internal.util.Preconditions.checkState; +import static com.android.server.companion.association.DisassociationProcessor.REASON_API; +import static com.android.server.companion.association.DisassociationProcessor.REASON_PKG_DATA_CLEARED; import static com.android.server.companion.utils.PackageUtils.enforceUsesCompanionDeviceFeature; import static com.android.server.companion.utils.PackageUtils.isRestrictedSettingsAllowed; import static com.android.server.companion.utils.PermissionsUtils.enforceCallerCanManageAssociationsForPackage; @@ -250,7 +252,7 @@ public class CompanionDeviceManagerService extends SystemService { + packageName + "]. Cleaning up CDM data..."); for (AssociationInfo association : associationsForPackage) { - mDisassociationProcessor.disassociate(association.getId()); + mDisassociationProcessor.disassociate(association.getId(), REASON_PKG_DATA_CLEARED); } mCompanionAppBinder.onPackageChanged(userId); @@ -426,7 +428,7 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void disassociate(int associationId) { - mDisassociationProcessor.disassociate(associationId); + mDisassociationProcessor.disassociate(associationId, REASON_API); } @Override diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java index e7d1460aa66a..c5ac7c31b5c3 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java @@ -18,6 +18,8 @@ package com.android.server.companion; import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_CONTEXT_SYNC; +import static com.android.server.companion.association.DisassociationProcessor.REASON_SHELL; + import android.companion.AssociationInfo; import android.companion.ContextSyncMessage; import android.companion.Flags; @@ -122,7 +124,7 @@ class CompanionDeviceShellCommand extends ShellCommand { if (association == null) { out.println("Association doesn't exist."); } else { - mDisassociationProcessor.disassociate(association.getId()); + mDisassociationProcessor.disassociate(association.getId(), REASON_SHELL); } } break; @@ -132,7 +134,7 @@ class CompanionDeviceShellCommand extends ShellCommand { final List<AssociationInfo> userAssociations = mAssociationStore.getAssociationsByUser(userId); for (AssociationInfo association : userAssociations) { - mDisassociationProcessor.disassociate(association.getId()); + mDisassociationProcessor.disassociate(association.getId(), REASON_SHELL); } } break; diff --git a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java index f2d019bde703..ce7dcd0fa1d4 100644 --- a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java +++ b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java @@ -58,6 +58,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; @@ -164,6 +165,7 @@ public final class AssociationDiskStore { private static final String FILE_NAME_LEGACY = "companion_device_manager_associations.xml"; private static final String FILE_NAME = "companion_device_manager.xml"; + private static final String FILE_NAME_LAST_REMOVED_ASSOCIATION = "last_removed_association.txt"; private static final String XML_TAG_STATE = "state"; private static final String XML_TAG_ASSOCIATIONS = "associations"; @@ -268,6 +270,46 @@ public final class AssociationDiskStore { } } + /** + * Read the last removed association from disk. + */ + public String readLastRemovedAssociation(@UserIdInt int userId) { + final AtomicFile file = createStorageFileForUser( + userId, FILE_NAME_LAST_REMOVED_ASSOCIATION); + StringBuilder sb = new StringBuilder(); + int c; + try (FileInputStream fis = file.openRead()) { + while ((c = fis.read()) != -1) { + sb.append((char) c); + } + fis.close(); + return sb.toString(); + } catch (FileNotFoundException e) { + Slog.e(TAG, "File " + file + " for user=" + userId + " doesn't exist."); + return null; + } catch (IOException e) { + Slog.e(TAG, "Can't read file " + file + " for user=" + userId); + return null; + } + } + + /** + * Write the last removed association to disk. + */ + public void writeLastRemovedAssociation(AssociationInfo association, String reason) { + Slog.i(TAG, "Writing last removed association=" + association.getId() + " to disk..."); + + final AtomicFile file = createStorageFileForUser( + association.getUserId(), FILE_NAME_LAST_REMOVED_ASSOCIATION); + writeToFileSafely(file, out -> { + out.write(String.valueOf(System.currentTimeMillis()).getBytes()); + out.write(' '); + out.write(reason.getBytes()); + out.write(' '); + out.write(association.toString().getBytes()); + }); + } + @NonNull private static Associations readAssociationsFromFile(@UserIdInt int userId, @NonNull AtomicFile file, @NonNull String rootTag) { diff --git a/services/companion/java/com/android/server/companion/association/AssociationStore.java b/services/companion/java/com/android/server/companion/association/AssociationStore.java index 757abd927ac8..f70c434e6b46 100644 --- a/services/companion/java/com/android/server/companion/association/AssociationStore.java +++ b/services/companion/java/com/android/server/companion/association/AssociationStore.java @@ -276,7 +276,7 @@ public class AssociationStore { /** * Remove an association. */ - public void removeAssociation(int id) { + public void removeAssociation(int id, String reason) { Slog.i(TAG, "Removing association id=[" + id + "]..."); final AssociationInfo association; @@ -291,6 +291,8 @@ public class AssociationStore { writeCacheToDisk(association.getUserId()); + mDiskStore.writeLastRemovedAssociation(association, reason); + Slog.i(TAG, "Done removing association."); } @@ -525,6 +527,14 @@ public class AssociationStore { out.append(" ").append(a.toString()).append('\n'); } } + + out.append("Last Removed Association:\n"); + for (UserInfo user : mUserManager.getAliveUsers()) { + String lastRemovedAssociation = mDiskStore.readLastRemovedAssociation(user.id); + if (lastRemovedAssociation != null) { + out.append(" ").append(lastRemovedAssociation).append('\n'); + } + } } private void broadcastChange(@ChangeType int changeType, AssociationInfo association) { diff --git a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java index 150e8da5f614..248056f32a4f 100644 --- a/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java +++ b/services/companion/java/com/android/server/companion/association/DisassociationProcessor.java @@ -47,6 +47,13 @@ import com.android.server.companion.transport.CompanionTransportManager; @SuppressLint("LongLogTag") public class DisassociationProcessor { + public static final String REASON_REVOKED = "revoked"; + public static final String REASON_SELF_IDLE = "self-idle"; + public static final String REASON_SHELL = "shell"; + public static final String REASON_LEGACY = "legacy"; + public static final String REASON_API = "api"; + public static final String REASON_PKG_DATA_CLEARED = "pkg-data-cleared"; + private static final String TAG = "CDM_DisassociationProcessor"; private static final String SYS_PROP_DEBUG_REMOVAL_TIME_WINDOW = @@ -94,7 +101,7 @@ public class DisassociationProcessor { * Disassociate an association by id. */ // TODO: also revoke notification access - public void disassociate(int id) { + public void disassociate(int id, String reason) { Slog.i(TAG, "Disassociating id=[" + id + "]..."); final AssociationInfo association = mAssociationStore.getAssociationWithCallerChecks(id); @@ -126,7 +133,7 @@ public class DisassociationProcessor { // Association cleanup. mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, id); - mAssociationStore.removeAssociation(association.getId()); + mAssociationStore.removeAssociation(association.getId(), reason); // If role is not in use by other associations, revoke the role. // Do not need to remove the system role since it was pre-granted by the system. @@ -151,7 +158,7 @@ public class DisassociationProcessor { } /** - * @deprecated Use {@link #disassociate(int)} instead. + * @deprecated Use {@link #disassociate(int, String)} instead. */ @Deprecated public void disassociate(int userId, String packageName, String macAddress) { @@ -165,7 +172,7 @@ public class DisassociationProcessor { mAssociationStore.getAssociationWithCallerChecks(association.getId()); - disassociate(association.getId()); + disassociate(association.getId(), REASON_LEGACY); } @SuppressLint("MissingPermission") @@ -223,7 +230,7 @@ public class DisassociationProcessor { Slog.i(TAG, "Removing inactive self-managed association=[" + association.toShortString() + "]."); - disassociate(id); + disassociate(id, REASON_SELF_IDLE); } } @@ -234,7 +241,7 @@ public class DisassociationProcessor { * * Lastly remove the role holder for the revoked associations for the same packages. * - * @see #disassociate(int) + * @see #disassociate(int, String) */ private class OnPackageVisibilityChangeListener implements ActivityManager.OnUidImportanceListener { @@ -260,7 +267,7 @@ public class DisassociationProcessor { int userId = UserHandle.getUserId(uid); for (AssociationInfo association : mAssociationStore.getRevokedAssociations(userId, packageName)) { - disassociate(association.getId()); + disassociate(association.getId(), REASON_REVOKED); } if (mAssociationStore.getRevokedAssociations().isEmpty()) { diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index f03e8c713228..28efdfc01ee2 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -163,6 +163,16 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub */ private static final long PENDING_TRAMPOLINE_TIMEOUT_MS = 5000; + /** + * Global lock for this Virtual Device. + * + * Never call outside this class while holding this lock. A number of other system services like + * WindowManager, DisplayManager, etc. call into this device to get device-specific information, + * while holding their own global locks. + * + * Making a call to another service while holding this lock creates lock order inversion and + * will potentially cause a deadlock. + */ private final Object mVirtualDeviceLock = new Object(); private final int mBaseVirtualDisplayFlags; @@ -179,14 +189,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub private final int mDeviceId; @Nullable private final String mPersistentDeviceId; - // Thou shall not hold the mVirtualDeviceLock over the mInputController calls. - // Holding the lock can lead to lock inversion with GlobalWindowManagerLock. - // 1. After display is created the window manager calls into VDM during construction - // of display specific context to fetch device id corresponding to the display. - // mVirtualDeviceLock will be held while this is done. - // 2. InputController interactions result in calls to DisplayManager (to set IME, - // possibly more indirect calls), and those attempt to lock GlobalWindowManagerLock which - // creates lock inversion. private final InputController mInputController; private final SensorController mSensorController; private final CameraAccessController mCameraAccessController; @@ -205,19 +207,23 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub private final DisplayManagerGlobal mDisplayManager; private final DisplayManagerInternal mDisplayManagerInternal; private final PowerManager mPowerManager; - @GuardedBy("mVirtualDeviceLock") + @GuardedBy("mIntentInterceptors") private final Map<IBinder, IntentFilter> mIntentInterceptors = new ArrayMap<>(); @NonNull private final Consumer<ArraySet<Integer>> mRunningAppsChangedCallback; + // The default setting for showing the pointer on new displays. @GuardedBy("mVirtualDeviceLock") private boolean mDefaultShowPointerIcon = true; @GuardedBy("mVirtualDeviceLock") @Nullable private LocaleList mLocaleList = null; - @GuardedBy("mVirtualDeviceLock") + + // Lock for power operations for this virtual device that allow calling PowerManager. + private final Object mPowerLock = new Object(); + @GuardedBy("mPowerLock") private boolean mLockdownActive = false; - @GuardedBy("mVirtualDeviceLock") + @GuardedBy("mPowerLock") private boolean mRequestedToBeAwake = true; @NonNull @@ -334,7 +340,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub */ @Override public boolean shouldInterceptIntent(@NonNull Intent intent) { - synchronized (mVirtualDeviceLock) { + synchronized (mIntentInterceptors) { boolean hasInterceptedIntent = false; for (Map.Entry<IBinder, IntentFilter> interceptor : mIntentInterceptors.entrySet()) { @@ -500,7 +506,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } void onLockdownChanged(boolean lockdownActive) { - synchronized (mVirtualDeviceLock) { + synchronized (mPowerLock) { if (lockdownActive != mLockdownActive) { mLockdownActive = lockdownActive; if (mLockdownActive) { @@ -610,7 +616,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Override // Binder call public void goToSleep() { checkCallerIsDeviceOwner(); - synchronized (mVirtualDeviceLock) { + synchronized (mPowerLock) { mRequestedToBeAwake = false; } final long ident = Binder.clearCallingIdentity(); @@ -624,7 +630,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Override // Binder call public void wakeUp() { checkCallerIsDeviceOwner(); - synchronized (mVirtualDeviceLock) { + synchronized (mPowerLock) { mRequestedToBeAwake = true; if (mLockdownActive) { Slog.w(TAG, "Cannot wake up device during lockdown."); @@ -850,8 +856,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub checkDisplayOwnedByVirtualDeviceLocked(displayId); if (mVirtualAudioController == null) { mVirtualAudioController = new VirtualAudioController(mContext, mAttributionSource); - GenericWindowPolicyController gwpc = mVirtualDisplays.get( - displayId).getWindowPolicyController(); + GenericWindowPolicyController gwpc = + mVirtualDisplays.get(displayId).getWindowPolicyController(); mVirtualAudioController.startListening(gwpc, routingCallback, configChangedCallback); } @@ -1293,7 +1299,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub checkCallerIsDeviceOwner(); Objects.requireNonNull(intentInterceptor); Objects.requireNonNull(filter); - synchronized (mVirtualDeviceLock) { + synchronized (mIntentInterceptors) { mIntentInterceptors.put(intentInterceptor.asBinder(), filter); } } @@ -1303,7 +1309,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @NonNull IVirtualDeviceIntentInterceptor intentInterceptor) { checkCallerIsDeviceOwner(); Objects.requireNonNull(intentInterceptor); - synchronized (mVirtualDeviceLock) { + synchronized (mIntentInterceptors) { mIntentInterceptors.remove(intentInterceptor.asBinder()); } } @@ -1653,6 +1659,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub void goToSleepInternal(@PowerManager.GoToSleepReason int reason) { final long now = SystemClock.uptimeMillis(); + IntArray displayIds = new IntArray(); synchronized (mVirtualDeviceLock) { for (int i = 0; i < mVirtualDisplays.size(); i++) { VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i); @@ -1660,13 +1667,17 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub continue; } int displayId = mVirtualDisplays.keyAt(i); - mPowerManager.goToSleep(displayId, now, reason, /* flags= */ 0); + displayIds.add(displayId); } } + for (int i = 0; i < displayIds.size(); ++i) { + mPowerManager.goToSleep(displayIds.get(i), now, reason, /* flags= */ 0); + } } void wakeUpInternal(@PowerManager.WakeReason int reason, String details) { final long now = SystemClock.uptimeMillis(); + IntArray displayIds = new IntArray(); synchronized (mVirtualDeviceLock) { for (int i = 0; i < mVirtualDisplays.size(); i++) { VirtualDisplayWrapper wrapper = mVirtualDisplays.valueAt(i); @@ -1674,9 +1685,12 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub continue; } int displayId = mVirtualDisplays.keyAt(i); - mPowerManager.wakeUp(now, reason, details, displayId); + displayIds.add(displayId); } } + for (int i = 0; i < displayIds.size(); ++i) { + mPowerManager.wakeUp(now, reason, details, displayIds.get(i)); + } } /** 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 ff82ca00b840..93b4de856463 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -117,7 +117,18 @@ public class VirtualDeviceManagerService extends SystemService { */ static final int CDM_ASSOCIATION_ID_NONE = 0; + /** + * Global VDM lock. + * + * Never call outside this class while holding this lock. A number of other system services like + * WindowManager, DisplayManager, etc. call into VDM to get device-specific information, while + * holding their own global locks. + * + * Making a call to another service while holding this lock creates lock order inversion and + * will potentially cause a deadlock. + */ private final Object mVirtualDeviceManagerLock = new Object(); + private final VirtualDeviceManagerImpl mImpl; private final VirtualDeviceManagerNativeImpl mNativeImpl; private final VirtualDeviceManagerInternal mLocalService; @@ -235,10 +246,9 @@ public class VirtualDeviceManagerService extends SystemService { // Called when the global lockdown state changes, i.e. lockdown is considered active if any user // is in lockdown mode, and inactive if no users are in lockdown mode. void onLockdownChanged(boolean lockdownActive) { - synchronized (mVirtualDeviceManagerLock) { - for (int i = 0; i < mVirtualDevices.size(); i++) { - mVirtualDevices.valueAt(i).onLockdownChanged(lockdownActive); - } + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + virtualDevicesSnapshot.get(i).onLockdownChanged(lockdownActive); } } @@ -264,16 +274,14 @@ public class VirtualDeviceManagerService extends SystemService { return null; } int userId = userHandle.getIdentifier(); - synchronized (mVirtualDeviceManagerLock) { - for (int i = 0; i < mVirtualDevices.size(); i++) { - final CameraAccessController cameraAccessController = - mVirtualDevices.valueAt(i).getCameraAccessController(); - if (cameraAccessController.getUserId() == userId) { - return cameraAccessController; - } + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + final CameraAccessController cameraAccessController = + virtualDevicesSnapshot.get(i).getCameraAccessController(); + if (cameraAccessController.getUserId() == userId) { + return cameraAccessController; } - } - Context userContext = getContext().createContextAsUser(userHandle, 0); + } Context userContext = getContext().createContextAsUser(userHandle, 0); return new CameraAccessController(userContext, mLocalService, this::onCameraAccessBlocked); } @@ -520,11 +528,10 @@ public class VirtualDeviceManagerService extends SystemService { @Override // Binder call public List<VirtualDevice> getVirtualDevices() { List<VirtualDevice> virtualDevices = new ArrayList<>(); - synchronized (mVirtualDeviceManagerLock) { - for (int i = 0; i < mVirtualDevices.size(); i++) { - final VirtualDeviceImpl device = mVirtualDevices.valueAt(i); - virtualDevices.add(device.getPublicVirtualDeviceObject()); - } + ArrayList<VirtualDeviceImpl> virtualDevicesSnapshot = getVirtualDevicesSnapshot(); + for (int i = 0; i < virtualDevicesSnapshot.size(); i++) { + VirtualDeviceImpl device = virtualDevicesSnapshot.get(i); + virtualDevices.add(device.getPublicVirtualDeviceObject()); } return virtualDevices; } @@ -834,15 +841,17 @@ public class VirtualDeviceManagerService extends SystemService { @Nullable public LocaleList getPreferredLocaleListForUid(int uid) { // TODO: b/263188984 support the case where an app is running on multiple VDs + VirtualDeviceImpl virtualDevice = null; synchronized (mVirtualDeviceManagerLock) { for (int i = 0; i < mAppsOnVirtualDevices.size(); i++) { if (mAppsOnVirtualDevices.valueAt(i).contains(uid)) { int deviceId = mAppsOnVirtualDevices.keyAt(i); - return mVirtualDevices.get(deviceId).getDeviceLocaleList(); + virtualDevice = mVirtualDevices.get(deviceId); + break; } } } - return null; + return virtualDevice == null ? null : virtualDevice.getDeviceLocaleList(); } @Override @@ -882,6 +891,11 @@ public class VirtualDeviceManagerService extends SystemService { } @Override + public VirtualDevice getVirtualDevice(int deviceId) { + return mImpl.getVirtualDevice(deviceId); + } + + @Override public long getDimDurationMillisForDeviceId(int deviceId) { VirtualDeviceImpl virtualDevice = getVirtualDeviceForId(deviceId); return virtualDevice == null ? -1 : virtualDevice.getDimDurationMillis(); diff --git a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java index 700a1624f7d4..7eb7072520de 100644 --- a/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java +++ b/services/contextualsearch/java/com/android/server/contextualsearch/ContextualSearchManagerService.java @@ -38,7 +38,6 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityOptions; import android.app.AppOpsManager; -import android.app.admin.DevicePolicyManagerInternal; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.contextualsearch.CallbackToken; @@ -67,6 +66,7 @@ import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ShellCallback; import android.os.SystemClock; +import android.os.UserManager; import android.provider.Settings; import android.util.Log; import android.util.Slog; @@ -112,8 +112,8 @@ public class ContextualSearchManagerService extends SystemService { private final ActivityTaskManagerInternal mAtmInternal; private final PackageManagerInternal mPackageManager; private final WindowManagerInternal mWmInternal; - private final DevicePolicyManagerInternal mDpmInternal; private final AudioManager mAudioManager; + private final UserManager mUserManager; private final Object mLock = new Object(); private final AssistDataRequester mAssistDataRequester; @@ -179,9 +179,9 @@ public class ContextualSearchManagerService extends SystemService { LocalServices.getService(ActivityTaskManagerInternal.class)); mPackageManager = LocalServices.getService(PackageManagerInternal.class); mAudioManager = context.getSystemService(AudioManager.class); + mUserManager = context.getSystemService(UserManager.class); mWmInternal = Objects.requireNonNull(LocalServices.getService(WindowManagerInternal.class)); - mDpmInternal = LocalServices.getService(DevicePolicyManagerInternal.class); mAssistDataRequester = new AssistDataRequester( mContext, IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE)), @@ -308,6 +308,11 @@ public class ContextualSearchManagerService extends SystemService { } } + @RequiresPermission(anyOf = { + android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.CREATE_USERS, + android.Manifest.permission.QUERY_USERS + }) private Intent getContextualSearchIntent(int entrypoint, int userId, CallbackToken mToken) { final Intent launchIntent = getResolvedLaunchIntent(userId); if (launchIntent == null) { @@ -338,8 +343,7 @@ public class ContextualSearchManagerService extends SystemService { visiblePackageNames.add(record.getComponentName().getPackageName()); activityTokens.add(record.getActivityToken()); } - if (mDpmInternal != null - && mDpmInternal.isUserOrganizationManaged(record.getUserId())) { + if (mUserManager.isManagedProfile(record.getUserId())) { isManagedProfileVisible = true; } } @@ -361,7 +365,7 @@ public class ContextualSearchManagerService extends SystemService { } } final ScreenshotHardwareBuffer shb = mWmInternal.takeContextualSearchScreenshot( - (Flags.contextualSearchWindowLayer() ? csUid : -1)); + (Flags.contextualSearchPreventSelfCapture() ? csUid : -1)); final Bitmap bm = shb != null ? shb.asBitmap() : null; // Now that everything is fetched, putting it in the launchIntent. if (bm != null) { @@ -507,7 +511,10 @@ public class ContextualSearchManagerService extends SystemService { Intent launchIntent = getContextualSearchIntent(entrypoint, callingUserId, mToken); if (launchIntent != null) { int result = invokeContextualSearchIntent(launchIntent, callingUserId); - if (DEBUG) Log.d(TAG, "Launch result: " + result); + if (DEBUG) { + Log.d(TAG, "Launch intent: " + launchIntent); + Log.d(TAG, "Launch result: " + result); + } } }); } @@ -542,7 +549,7 @@ public class ContextualSearchManagerService extends SystemService { Binder.withCleanCallingIdentity(() -> { final ScreenshotHardwareBuffer shb = mWmInternal.takeContextualSearchScreenshot( - (Flags.contextualSearchWindowLayer() ? callingUid : -1)); + (Flags.contextualSearchPreventSelfCapture() ? callingUid : -1)); final Bitmap bm = shb != null ? shb.asBitmap() : null; if (bm != null) { bundle.putParcelable(ContextualSearchManager.EXTRA_SCREENSHOT, diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java index 04edb5756599..cd632e638281 100644 --- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java +++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java @@ -31,6 +31,8 @@ import static com.android.server.wm.WindowManagerInternal.OnWindowRemovedListene import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.role.RoleManager; +import android.companion.AssociationRequest; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -81,6 +83,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic private PackageManagerInternal mPackageManagerInternal; + private RoleManager mRoleManager; + @Nullable private WindowManagerInternal mWindowManager; @@ -225,7 +229,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic } @Override - public void onStart() {} + public void onStart() { + } @Override public void onBootPhase(int phase) { @@ -237,6 +242,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic init(getContext().getSystemService(MediaProjectionManager.class), LocalServices.getService(WindowManagerInternal.class), LocalServices.getService(PackageManagerInternal.class), + getContext().getSystemService(RoleManager.class), getExemptedPackages() ); if (sensitiveContentAppProtection()) { @@ -247,7 +253,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic @VisibleForTesting void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager, - PackageManagerInternal packageManagerInternal, ArraySet<String> exemptedPackages) { + PackageManagerInternal packageManagerInternal, RoleManager roleManager, + ArraySet<String> exemptedPackages) { if (DEBUG) Log.d(TAG, "init"); Objects.requireNonNull(projectionManager); @@ -256,6 +263,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic mProjectionManager = projectionManager; mWindowManager = windowManager; mPackageManagerInternal = packageManagerInternal; + mRoleManager = roleManager; mExemptedPackages = exemptedPackages; // TODO(b/317250444): use MediaProjectionManagerService directly, reduces unnecessary @@ -312,8 +320,10 @@ public final class SensitiveContentProtectionManagerService extends SystemServic boolean isPackageExempted = (mExemptedPackages != null && mExemptedPackages.contains( projectionInfo.getPackageName())) || canRecordSensitiveContent(projectionInfo.getPackageName()) + || holdsAppStreamingRole(projectionInfo.getPackageName(), + projectionInfo.getUserHandle()) || isAutofillServiceRecorderPackage(projectionInfo.getUserHandle().getIdentifier(), - projectionInfo.getPackageName()); + projectionInfo.getPackageName()); // TODO(b/324447419): move GlobalSettings lookup to background thread boolean isFeatureDisabled = Settings.Global.getInt(getContext().getContentResolver(), DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0; @@ -348,6 +358,11 @@ public final class SensitiveContentProtectionManagerService extends SystemServic } } + private boolean holdsAppStreamingRole(String packageName, UserHandle userHandle) { + return mRoleManager.getRoleHoldersAsUser( + AssociationRequest.DEVICE_PROFILE_APP_STREAMING, userHandle).contains(packageName); + } + private void onProjectionEnd() { synchronized (mSensitiveContentProtectionLock) { mProjectionActive = false; diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index d2a5734f323f..b6fe0ad37078 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -49,7 +49,6 @@ import static com.android.internal.util.XmlUtils.writeStringAttribute; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.START_TAG; -import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; @@ -2443,6 +2442,7 @@ class StorageManagerService extends IStorageManager.Stub } catch (Installer.InstallerException e) { Slog.e(TAG, "Failed unmount mirror data", e); } + extendWatchdogTimeout("#unmount might be slow"); mVold.unmount(vol.getId()); mStorageSessionController.onVolumeUnmount(vol.getImmutableVolumeInfo()); } catch (Exception e) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index cce29592d912..125824c3f37e 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -618,7 +618,7 @@ public final class ActiveServices { Slog.i(TAG, " Stopping fg for service " + r); } setServiceForegroundInnerLocked(r, 0, null, 0, 0, - 0); + 0, /* systemRequestedTransition= */ true); } } @@ -1839,7 +1839,7 @@ public final class ActiveServices { ServiceRecord r = findServiceLocked(className, token, userId); if (r != null) { setServiceForegroundInnerLocked(r, id, notification, flags, foregroundServiceType, - callingUid); + callingUid, /* systemRequestedTransition= */ false); } } finally { mAm.mInjector.restoreCallingIdentity(origId); @@ -2155,7 +2155,7 @@ public final class ActiveServices { @GuardedBy("mAm") private void setServiceForegroundInnerLocked(final ServiceRecord r, int id, Notification notification, int flags, int foregroundServiceType, - int callingUidIfStart) { + int callingUidIfStart, boolean systemRequestedTransition) { if (id != 0) { if (notification == null) { throw new IllegalArgumentException("null notification"); @@ -2800,6 +2800,7 @@ public final class ActiveServices { // earlier. r.foregroundServiceType = 0; r.mFgsNotificationWasDeferred = false; + r.systemRequestedFgToBg = systemRequestedTransition; signalForegroundServiceObserversLocked(r); resetFgsRestrictionLocked(r); mAm.updateForegroundServiceUsageStats(r.name, r.userId, false); @@ -9339,14 +9340,22 @@ public final class ActiveServices { if (sr.foregroundServiceType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE && sr.foregroundId == notificationId) { - if (DEBUG_FOREGROUND_SERVICE) { - Slog.d(TAG, "Moving media service to foreground for package " - + packageName); + // check if service is explicitly requested by app to not be in foreground. + if (sr.systemRequestedFgToBg) { + Slog.d(TAG, + "System initiated service transition to foreground " + + "for package " + + packageName); + setServiceForegroundInnerLocked(sr, sr.foregroundId, + sr.foregroundNoti, /* flags */ 0, + ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, + /* callingUidStart */ 0, /* systemRequestedTransition */ true); + } else { + Slog.d(TAG, + "Ignoring system initiated foreground service transition for " + + "package" + + packageName); } - setServiceForegroundInnerLocked(sr, sr.foregroundId, - sr.foregroundNoti, /* flags */ 0, - ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK, - /* callingUidStart */ 0); } } } @@ -9379,13 +9388,14 @@ public final class ActiveServices { if (sr.foregroundServiceType == ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK && sr.foregroundId == notificationId) { - if (DEBUG_FOREGROUND_SERVICE) { - Slog.d(TAG, "Forcing media foreground service to background for package " - + packageName); - } + Slog.d(TAG, + "System initiated transition of foreground service(type:media) to bg " + + "for package" + + packageName); setServiceForegroundInnerLocked(sr, /* id */ 0, /* notification */ null, /* flags */ 0, - /* foregroundServiceType */ 0, /* callingUidStart */ 0); + /* foregroundServiceType */ 0, /* callingUidStart */ 0, + /* systemRequestedTransition */ true); } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6e3d7bd19b41..07a4d52f56ec 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -301,6 +301,7 @@ import android.content.pm.ProviderInfoList; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; +import android.content.pm.SystemFeaturesCache; import android.content.pm.TestUtilityService; import android.content.pm.UserInfo; import android.content.pm.UserProperties; @@ -2559,9 +2560,20 @@ public class ActivityManagerService extends IActivityManager.Stub mTraceErrorLogger = new TraceErrorLogger(); mComponentAliasResolver = new ComponentAliasResolver(this); sCreatorTokenCacheCleaner = new Handler(mHandlerThread.getLooper()); + + ApplicationSharedMemory applicationSharedMemory = ApplicationSharedMemory.getInstance(); + if (android.content.pm.Flags.cacheSdkSystemFeatures()) { + // Install the cache into the process-wide singleton for in-proc queries, as well as + // shared memory. Apps will inflate the cache from shared memory in bindApplication. + SystemFeaturesCache systemFeaturesCache = + new SystemFeaturesCache(SystemConfig.getInstance().getAvailableFeatures()); + SystemFeaturesCache.setInstance(systemFeaturesCache); + applicationSharedMemory.writeSystemFeaturesCache( + systemFeaturesCache.getSdkFeatureVersions()); + } try { mApplicationSharedMemoryReadOnlyFd = - ApplicationSharedMemory.getInstance().getReadOnlyFileDescriptor(); + applicationSharedMemory.getReadOnlyFileDescriptor(); } catch (IOException e) { Slog.e(TAG, "Failed to get read only fd for shared memory", e); throw new RuntimeException(e); diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index b677297dfef2..4bfee1d8398f 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -1464,7 +1464,10 @@ public class CachedAppOptimizer { void onProcessFrozen(ProcessRecord frozenProc) { if (useCompaction()) { synchronized (mProcLock) { - compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false); + // only full-compact if process is cached + if (frozenProc.mState.getSetAdj() >= mCompactThrottleMinOomAdj) { + compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false); + } } } frozenProc.onProcessFrozen(); diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index cc6fabc8fd67..4b6d6bc955cc 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -68,7 +68,7 @@ per-file CarUserSwitchingDialog.java = file:platform/packages/services/Car:/OWNE per-file ActivityManager* = file:/ACTIVITY_SECURITY_OWNERS # Aconfig Flags -per-file flags.aconfig = yamasani@google.com, bills@google.com, nalini@google.com +per-file flags.aconfig = yamasani@google.com, nalini@google.com # Londoners michaelwr@google.com #{LAST_RESORT_SUGGESTION} @@ -77,4 +77,4 @@ narayan@google.com #{LAST_RESORT_SUGGESTION} # Default yamasani@google.com hackbod@google.com #{LAST_RESORT_SUGGESTION} -omakoto@google.com #{LAST_RESORT_SUGGESTION}
\ No newline at end of file +omakoto@google.com #{LAST_RESORT_SUGGESTION} diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 61c5501a7b5a..13d367a95942 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -446,6 +446,8 @@ public class OomAdjuster { private static final int CACHING_UI_SERVICE_CLIENT_ADJ_THRESHOLD = Flags.raiseBoundUiServiceThreshold() ? SERVICE_ADJ : PERCEPTIBLE_APP_ADJ; + static final long PERCEPTIBLE_TASK_TIMEOUT_MILLIS = 5 * 60 * 1000; + @VisibleForTesting public static class Injector { boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId, @@ -1847,7 +1849,7 @@ public class OomAdjuster { mHasVisibleActivities = false; } - void onOtherActivity() { + void onOtherActivity(long perceptibleTaskStoppedTimeMillis) { if (procState > PROCESS_STATE_CACHED_ACTIVITY) { procState = PROCESS_STATE_CACHED_ACTIVITY; mAdjType = "cch-act"; @@ -1856,6 +1858,28 @@ public class OomAdjuster { "Raise procstate to cached activity: " + app); } } + if (Flags.perceptibleTasks() && adj > PERCEPTIBLE_MEDIUM_APP_ADJ) { + if (perceptibleTaskStoppedTimeMillis >= 0) { + final long now = mInjector.getUptimeMillis(); + if (now - perceptibleTaskStoppedTimeMillis < PERCEPTIBLE_TASK_TIMEOUT_MILLIS) { + adj = PERCEPTIBLE_MEDIUM_APP_ADJ; + mAdjType = "perceptible-act"; + if (procState > PROCESS_STATE_IMPORTANT_BACKGROUND) { + procState = PROCESS_STATE_IMPORTANT_BACKGROUND; + } + + maybeSetProcessFollowUpUpdateLocked(app, + perceptibleTaskStoppedTimeMillis + PERCEPTIBLE_TASK_TIMEOUT_MILLIS, + now); + } else if (adj > PREVIOUS_APP_ADJ) { + adj = PREVIOUS_APP_ADJ; + mAdjType = "stale-perceptible-act"; + if (procState > PROCESS_STATE_LAST_ACTIVITY) { + procState = PROCESS_STATE_LAST_ACTIVITY; + } + } + } + } mHasVisibleActivities = false; } } diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java index b0f808b39053..25175e6bee5f 100644 --- a/services/core/java/com/android/server/am/ProcessStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessStateRecord.java @@ -1120,7 +1120,8 @@ final class ProcessStateRecord { } else if ((flags & ACTIVITY_STATE_FLAG_IS_STOPPING) != 0) { callback.onStoppingActivity((flags & ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) != 0); } else { - callback.onOtherActivity(); + final long ts = mApp.getWindowProcessController().getPerceptibleTaskStoppedTimeMillis(); + callback.onOtherActivity(ts); } mCachedAdj = callback.adj; diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index ca34a13c55b1..f443e4455734 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -158,6 +158,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN boolean fgWaiting; // is a timeout for going foreground already scheduled? boolean isNotAppComponentUsage; // is service binding not considered component/package usage? boolean isForeground; // is service currently in foreground mode? + boolean systemRequestedFgToBg; // system requested service to transition to background. boolean inSharedIsolatedProcess; // is the service in a shared isolated process int foregroundId; // Notification ID of last foreground req. Notification foregroundNoti; // Notification record of foreground state. diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig index 27c384a22fb6..c8fedf3d1765 100644 --- a/services/core/java/com/android/server/am/flags.aconfig +++ b/services/core/java/com/android/server/am/flags.aconfig @@ -293,6 +293,13 @@ flag { } flag { + name: "perceptible_tasks" + namespace: "system_performance" + description: "Boost the oom_score_adj of activities in perceptible tasks" + bug: "370890207" +} + +flag { name: "expedite_activity_launch_on_cold_start" namespace: "system_performance" description: "Notify ActivityTaskManager of cold starts early to fix app launch behavior." diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 6d6e1fb6bfb3..ef80d59993e9 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -18,6 +18,7 @@ package com.android.server.audio; import static android.media.audio.Flags.scoManagedByAudio; import static com.android.media.audio.Flags.equalScoLeaVcIndexRange; +import static com.android.media.audio.Flags.optimizeBtDeviceSwitch; import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_HEADSET; import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_BLE_SPEAKER; import static com.android.server.audio.AudioService.BT_COMM_DEVICE_ACTIVE_SCO; @@ -290,8 +291,8 @@ public class AudioDeviceBroker { } @GuardedBy("mDeviceStateLock") - /*package*/ void onSetBtScoActiveDevice(BluetoothDevice btDevice) { - mBtHelper.onSetBtScoActiveDevice(btDevice); + /*package*/ void onSetBtScoActiveDevice(BluetoothDevice btDevice, boolean deviceSwitch) { + mBtHelper.onSetBtScoActiveDevice(btDevice, deviceSwitch); } /*package*/ void setBluetoothA2dpOn_Async(boolean on, String source) { @@ -941,6 +942,7 @@ public class AudioDeviceBroker { final @NonNull String mEventSource; final int mAudioSystemDevice; final int mMusicDevice; + final boolean mIsDeviceSwitch; BtDeviceInfo(@NonNull BtDeviceChangedData d, @NonNull BluetoothDevice device, int state, int audioDevice, @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) { @@ -953,6 +955,8 @@ public class AudioDeviceBroker { mEventSource = d.mEventSource; mAudioSystemDevice = audioDevice; mMusicDevice = AudioSystem.DEVICE_NONE; + mIsDeviceSwitch = optimizeBtDeviceSwitch() + && d.mNewDevice != null && d.mPreviousDevice != null; } // constructor used by AudioDeviceBroker to search similar message @@ -966,6 +970,7 @@ public class AudioDeviceBroker { mSupprNoisy = false; mVolume = -1; mIsLeOutput = false; + mIsDeviceSwitch = false; } // constructor used by AudioDeviceInventory when config change failed @@ -980,6 +985,7 @@ public class AudioDeviceBroker { mSupprNoisy = false; mVolume = -1; mIsLeOutput = false; + mIsDeviceSwitch = false; } BtDeviceInfo(@NonNull BtDeviceInfo src, int state) { @@ -992,6 +998,7 @@ public class AudioDeviceBroker { mEventSource = src.mEventSource; mAudioSystemDevice = src.mAudioSystemDevice; mMusicDevice = src.mMusicDevice; + mIsDeviceSwitch = false; } // redefine equality op so we can match messages intended for this device @@ -1026,7 +1033,8 @@ public class AudioDeviceBroker { + " isLeOutput=" + mIsLeOutput + " eventSource=" + mEventSource + " audioSystemDevice=" + mAudioSystemDevice - + " musicDevice=" + mMusicDevice; + + " musicDevice=" + mMusicDevice + + " isDeviceSwitch=" + mIsDeviceSwitch; } } @@ -1196,6 +1204,8 @@ public class AudioDeviceBroker { AudioSystem.setParameters("A2dpSuspended=true"); AudioSystem.setParameters("LeAudioSuspended=true"); AudioSystem.setParameters("BT_SCO=on"); + mBluetoothA2dpSuspendedApplied = true; + mBluetoothLeSuspendedApplied = true; } else { AudioSystem.setParameters("BT_SCO=off"); if (mBluetoothA2dpSuspendedApplied) { @@ -1680,10 +1690,11 @@ public class AudioDeviceBroker { } /*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes, - boolean connect, @Nullable BluetoothDevice btDevice) { + boolean connect, @Nullable BluetoothDevice btDevice, + boolean deviceSwitch) { synchronized (mDeviceStateLock) { return mDeviceInventory.handleDeviceConnection( - attributes, connect, false /*for test*/, btDevice); + attributes, connect, false /*for test*/, btDevice, deviceSwitch); } } @@ -1776,6 +1787,18 @@ public class AudioDeviceBroker { pw.println("\n" + prefix + "mScoManagedByAudio: " + mScoManagedByAudio); + pw.println("\n" + prefix + "Bluetooth SCO on" + + ", requested: " + mBluetoothScoOn + + ", applied: " + mBluetoothScoOnApplied); + pw.println("\n" + prefix + "Bluetooth A2DP suspended" + + ", requested ext: " + mBluetoothA2dpSuspendedExt + + ", requested int: " + mBluetoothA2dpSuspendedInt + + ", applied " + mBluetoothA2dpSuspendedApplied); + pw.println("\n" + prefix + "Bluetooth LE Audio suspended" + + ", requested ext: " + mBluetoothLeSuspendedExt + + ", requested int: " + mBluetoothLeSuspendedInt + + ", applied " + mBluetoothLeSuspendedApplied); + mBtHelper.dump(pw, prefix); } @@ -1930,10 +1953,12 @@ public class AudioDeviceBroker { || btInfo.mIsLeOutput) ? mAudioService.getBluetoothContextualVolumeStream() : AudioSystem.STREAM_DEFAULT); - if (btInfo.mProfile == BluetoothProfile.LE_AUDIO + if ((btInfo.mProfile == BluetoothProfile.LE_AUDIO || btInfo.mProfile == BluetoothProfile.HEARING_AID || (mScoManagedByAudio - && btInfo.mProfile == BluetoothProfile.HEADSET)) { + && btInfo.mProfile == BluetoothProfile.HEADSET)) + && (btInfo.mState == BluetoothProfile.STATE_CONNECTED + || !btInfo.mIsDeviceSwitch)) { onUpdateCommunicationRouteClient( bluetoothScoRequestOwnerAttributionSource(), "setBluetoothActiveDevice"); diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index ef10793fd955..ae91934e7498 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -799,7 +799,7 @@ public class AudioDeviceInventory { di.mDeviceAddress, di.mDeviceName), AudioSystem.DEVICE_STATE_AVAILABLE, - di.mDeviceCodecFormat); + di.mDeviceCodecFormat, false /*deviceSwitch*/); if (asDeviceConnectionFailure() && res != AudioSystem.AUDIO_STATUS_OK) { failedReconnectionDeviceList.add(di); } @@ -811,7 +811,7 @@ public class AudioDeviceInventory { EventLogger.Event.ALOGE, TAG); mConnectedDevices.remove(di.getKey(), di); if (AudioSystem.isBluetoothScoDevice(di.mDeviceType)) { - mDeviceBroker.onSetBtScoActiveDevice(null); + mDeviceBroker.onSetBtScoActiveDevice(null, false /*deviceSwitch*/); } } } @@ -851,7 +851,8 @@ public class AudioDeviceInventory { Log.d(TAG, "onSetBtActiveDevice" + " btDevice=" + btInfo.mDevice + " profile=" + BluetoothProfile.getProfileName(btInfo.mProfile) - + " state=" + BluetoothProfile.getConnectionStateName(btInfo.mState)); + + " state=" + BluetoothProfile.getConnectionStateName(btInfo.mState) + + " isDeviceSwitch=" + btInfo.mIsDeviceSwitch); } String address = btInfo.mDevice.getAddress(); if (!BluetoothAdapter.checkBluetoothAddress(address)) { @@ -897,7 +898,8 @@ public class AudioDeviceInventory { break; case BluetoothProfile.A2DP: if (switchToUnavailable) { - makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat); + makeA2dpDeviceUnavailableNow(address, di.mDeviceCodecFormat, + btInfo.mIsDeviceSwitch); } else if (switchToAvailable) { // device is not already connected if (btInfo.mVolume != -1) { @@ -911,7 +913,7 @@ public class AudioDeviceInventory { break; case BluetoothProfile.HEARING_AID: if (switchToUnavailable) { - makeHearingAidDeviceUnavailable(address); + makeHearingAidDeviceUnavailable(address, btInfo.mIsDeviceSwitch); } else if (switchToAvailable) { makeHearingAidDeviceAvailable(address, BtHelper.getName(btInfo.mDevice), streamType, "onSetBtActiveDevice"); @@ -921,7 +923,8 @@ public class AudioDeviceInventory { case BluetoothProfile.LE_AUDIO_BROADCAST: if (switchToUnavailable) { makeLeAudioDeviceUnavailableNow(address, - btInfo.mAudioSystemDevice, di.mDeviceCodecFormat); + btInfo.mAudioSystemDevice, di.mDeviceCodecFormat, + btInfo.mIsDeviceSwitch); } else if (switchToAvailable) { makeLeAudioDeviceAvailable( btInfo, streamType, codec, "onSetBtActiveDevice"); @@ -930,9 +933,10 @@ public class AudioDeviceInventory { case BluetoothProfile.HEADSET: if (mDeviceBroker.isScoManagedByAudio()) { if (switchToUnavailable) { - mDeviceBroker.onSetBtScoActiveDevice(null); + mDeviceBroker.onSetBtScoActiveDevice(null, btInfo.mIsDeviceSwitch); } else if (switchToAvailable) { - mDeviceBroker.onSetBtScoActiveDevice(btInfo.mDevice); + mDeviceBroker.onSetBtScoActiveDevice( + btInfo.mDevice, false /*deviceSwitch*/); } } break; @@ -1053,19 +1057,19 @@ public class AudioDeviceInventory { /*package*/ void onMakeA2dpDeviceUnavailableNow(String address, int a2dpCodec) { synchronized (mDevicesLock) { - makeA2dpDeviceUnavailableNow(address, a2dpCodec); + makeA2dpDeviceUnavailableNow(address, a2dpCodec, false /*deviceSwitch*/); } } /*package*/ void onMakeLeAudioDeviceUnavailableNow(String address, int device, int codec) { synchronized (mDevicesLock) { - makeLeAudioDeviceUnavailableNow(address, device, codec); + makeLeAudioDeviceUnavailableNow(address, device, codec, false /*deviceSwitch*/); } } /*package*/ void onMakeHearingAidDeviceUnavailableNow(String address) { synchronized (mDevicesLock) { - makeHearingAidDeviceUnavailable(address); + makeHearingAidDeviceUnavailable(address, false /*deviceSwitch*/); } } @@ -1180,7 +1184,8 @@ public class AudioDeviceInventory { } if (!handleDeviceConnection(wdcs.mAttributes, - wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest, null)) { + wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest, + null, false /*deviceSwitch*/)) { // change of connection state failed, bailout mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed") .record(); @@ -1788,14 +1793,15 @@ public class AudioDeviceInventory { */ /*package*/ boolean handleDeviceConnection(@NonNull AudioDeviceAttributes attributes, boolean connect, boolean isForTesting, - @Nullable BluetoothDevice btDevice) { + @Nullable BluetoothDevice btDevice, + boolean deviceSwitch) { int device = attributes.getInternalType(); String address = attributes.getAddress(); String deviceName = attributes.getName(); if (AudioService.DEBUG_DEVICES) { Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device) + " address:" + address - + " name:" + deviceName + ")"); + + " name:" + deviceName + ", deviceSwitch: " + deviceSwitch + ")"); } MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "handleDeviceConnection") .set(MediaMetrics.Property.ADDRESS, address) @@ -1829,7 +1835,8 @@ public class AudioDeviceInventory { res = AudioSystem.AUDIO_STATUS_OK; } else { res = mAudioSystem.setDeviceConnectionState(attributes, - AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT); + AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT, + false /*deviceSwitch*/); } if (res != AudioSystem.AUDIO_STATUS_OK) { final String reason = "not connecting device 0x" + Integer.toHexString(device) @@ -1856,7 +1863,8 @@ public class AudioDeviceInventory { status = true; } else if (!connect && isConnected) { mAudioSystem.setDeviceConnectionState(attributes, - AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT); + AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT, + deviceSwitch); // always remove even if disconnection failed mConnectedDevices.remove(deviceKey); mDeviceBroker.postCheckCommunicationDeviceRemoval(attributes); @@ -2030,7 +2038,7 @@ public class AudioDeviceInventory { } } if (disconnect) { - mDeviceBroker.onSetBtScoActiveDevice(null); + mDeviceBroker.onSetBtScoActiveDevice(null, false /*deviceSwitch*/); } } @@ -2068,7 +2076,8 @@ public class AudioDeviceInventory { || info.mProfile == BluetoothProfile.LE_AUDIO_BROADCAST) && info.mIsLeOutput) || info.mProfile == BluetoothProfile.HEARING_AID - || info.mProfile == BluetoothProfile.A2DP)) { + || info.mProfile == BluetoothProfile.A2DP) + && !info.mIsDeviceSwitch) { @AudioService.ConnectionState int asState = (info.mState == BluetoothProfile.STATE_CONNECTED) ? AudioService.CONNECTION_STATE_CONNECTED @@ -2124,7 +2133,7 @@ public class AudioDeviceInventory { AudioDeviceAttributes ada = new AudioDeviceAttributes( AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name); final int res = mAudioSystem.setDeviceConnectionState(ada, - AudioSystem.DEVICE_STATE_AVAILABLE, codec); + AudioSystem.DEVICE_STATE_AVAILABLE, codec, false); // TODO: log in MediaMetrics once distinction between connection failure and // double connection is made. @@ -2362,7 +2371,7 @@ public class AudioDeviceInventory { } @GuardedBy("mDevicesLock") - private void makeA2dpDeviceUnavailableNow(String address, int codec) { + private void makeA2dpDeviceUnavailableNow(String address, int codec, boolean deviceSwitch) { MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId + "a2dp." + address) .set(MediaMetrics.Property.ENCODING, AudioSystem.audioFormatToString(codec)) .set(MediaMetrics.Property.EVENT, "makeA2dpDeviceUnavailableNow"); @@ -2393,7 +2402,7 @@ public class AudioDeviceInventory { AudioDeviceAttributes ada = new AudioDeviceAttributes( AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address); final int res = mAudioSystem.setDeviceConnectionState(ada, - AudioSystem.DEVICE_STATE_UNAVAILABLE, codec); + AudioSystem.DEVICE_STATE_UNAVAILABLE, codec, deviceSwitch); if (res != AudioSystem.AUDIO_STATUS_OK) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( @@ -2404,7 +2413,8 @@ public class AudioDeviceInventory { } else { AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent( "A2DP device addr=" + Utils.anonymizeBluetoothAddress(address) - + " made unavailable")).printSlog(EventLogger.Event.ALOGI, TAG)); + + " made unavailable, deviceSwitch" + deviceSwitch)) + .printSlog(EventLogger.Event.ALOGI, TAG)); } mApmConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); @@ -2440,7 +2450,7 @@ public class AudioDeviceInventory { final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes( AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address), AudioSystem.DEVICE_STATE_AVAILABLE, - AudioSystem.AUDIO_FORMAT_DEFAULT); + AudioSystem.AUDIO_FORMAT_DEFAULT, false); if (res != AudioSystem.AUDIO_STATUS_OK) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "APM failed to make available A2DP source device addr=" @@ -2465,7 +2475,7 @@ public class AudioDeviceInventory { AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address); mAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_UNAVAILABLE, - AudioSystem.AUDIO_FORMAT_DEFAULT); + AudioSystem.AUDIO_FORMAT_DEFAULT, false); // always remove regardless of the result mConnectedDevices.remove( DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address)); @@ -2485,7 +2495,7 @@ public class AudioDeviceInventory { DEVICE_OUT_HEARING_AID, address, name); final int res = mAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_AVAILABLE, - AudioSystem.AUDIO_FORMAT_DEFAULT); + AudioSystem.AUDIO_FORMAT_DEFAULT, false); if (asDeviceConnectionFailure() && res != AudioSystem.AUDIO_STATUS_OK) { AudioService.sDeviceLogger.enqueueAndSlog( "APM failed to make available HearingAid addr=" + address @@ -2515,12 +2525,12 @@ public class AudioDeviceInventory { } @GuardedBy("mDevicesLock") - private void makeHearingAidDeviceUnavailable(String address) { + private void makeHearingAidDeviceUnavailable(String address, boolean deviceSwitch) { AudioDeviceAttributes ada = new AudioDeviceAttributes( DEVICE_OUT_HEARING_AID, address); mAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_UNAVAILABLE, - AudioSystem.AUDIO_FORMAT_DEFAULT); + AudioSystem.AUDIO_FORMAT_DEFAULT, deviceSwitch); // always remove regardless of return code mConnectedDevices.remove( DeviceInfo.makeDeviceListKey(DEVICE_OUT_HEARING_AID, address)); @@ -2622,7 +2632,7 @@ public class AudioDeviceInventory { AudioDeviceAttributes ada = new AudioDeviceAttributes(device, address, name); final int res = mAudioSystem.setDeviceConnectionState(ada, - AudioSystem.DEVICE_STATE_AVAILABLE, codec); + AudioSystem.DEVICE_STATE_AVAILABLE, codec, false /*deviceSwitch*/); if (res != AudioSystem.AUDIO_STATUS_OK) { AudioService.sDeviceLogger.enqueueAndSlog( "APM failed to make available LE Audio device addr=" + address @@ -2669,13 +2679,13 @@ public class AudioDeviceInventory { @GuardedBy("mDevicesLock") private void makeLeAudioDeviceUnavailableNow(String address, int device, - @AudioSystem.AudioFormatNativeEnumForBtCodec int codec) { + @AudioSystem.AudioFormatNativeEnumForBtCodec int codec, boolean deviceSwitch) { AudioDeviceAttributes ada = null; if (device != AudioSystem.DEVICE_NONE) { ada = new AudioDeviceAttributes(device, address); final int res = mAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_UNAVAILABLE, - codec); + codec, deviceSwitch); if (res != AudioSystem.AUDIO_STATUS_OK) { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( @@ -2685,7 +2695,8 @@ public class AudioDeviceInventory { } else { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( "LE Audio device addr=" + Utils.anonymizeBluetoothAddress(address) - + " made unavailable").printSlog(EventLogger.Event.ALOGI, TAG)); + + " made unavailable, deviceSwitch" + deviceSwitch) + .printSlog(EventLogger.Event.ALOGI, TAG)); } mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address)); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 86871ea45d13..d800503c658e 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -63,6 +63,7 @@ import static com.android.media.audio.Flags.audioserverPermissions; import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume; import static com.android.media.audio.Flags.deferWearPermissionUpdates; import static com.android.media.audio.Flags.equalScoLeaVcIndexRange; +import static com.android.media.audio.Flags.optimizeBtDeviceSwitch; import static com.android.media.audio.Flags.replaceStreamBtSco; import static com.android.media.audio.Flags.ringMyCar; import static com.android.media.audio.Flags.ringerModeAffectsAlarm; @@ -585,6 +586,9 @@ public class AudioService extends IAudioService.Stub // protects mRingerMode private final Object mSettingsLock = new Object(); + // protects VolumeStreamState / VolumeGroupState operations + private final Object mVolumeStateLock = new Object(); + /** Maximum volume index values for audio streams */ protected static int[] MAX_STREAM_VOLUME = new int[] { 5, // STREAM_VOICE_CALL @@ -1611,7 +1615,7 @@ public class AudioService extends IAudioService.Stub private void initVolumeStreamStates() { int numStreamTypes = AudioSystem.getNumStreamTypes(); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { final VolumeStreamState streamState = getVssForStream(streamType); if (streamState == null) { @@ -2419,7 +2423,7 @@ public class AudioService extends IAudioService.Stub private void checkAllAliasStreamVolumes() { synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { int streamAlias = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1); @@ -2501,7 +2505,7 @@ public class AudioService extends IAudioService.Stub private void onUpdateVolumeStatesForAudioDevice(int device, String caller) { final int numStreamTypes = AudioSystem.getNumStreamTypes(); synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { for (int streamType = 0; streamType < numStreamTypes; streamType++) { updateVolumeStates(device, streamType, caller); } @@ -2770,7 +2774,7 @@ public class AudioService extends IAudioService.Stub updateDefaultVolumes(); synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { getVssForStreamOrDefault(AudioSystem.STREAM_DTMF) .setAllIndexes(getVssForStreamOrDefault(dtmfStreamAlias), caller); getVssForStreamOrDefault(AudioSystem.STREAM_ACCESSIBILITY).setSettingName( @@ -3232,8 +3236,10 @@ public class AudioService extends IAudioService.Stub // Each stream will read its own persisted settings // Broadcast the sticky intents - broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal); - broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode); + synchronized (mSettingsLock) { + broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal); + broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode); + } // Broadcast vibrate settings broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); @@ -4235,7 +4241,7 @@ public class AudioService extends IAudioService.Stub private void muteAliasStreams(int streamAlias, boolean state) { // Locking mSettingsLock to avoid inversion when calling doMute -> updateVolumeGroupIndex synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { List<Integer> streamsToMute = new ArrayList<>(); for (int streamIdx = 0; streamIdx < mStreamStates.size(); streamIdx++) { final VolumeStreamState vss = mStreamStates.valueAt(streamIdx); @@ -4279,7 +4285,7 @@ public class AudioService extends IAudioService.Stub // Locking mSettingsLock to avoid inversion when calling vss.mute -> vss.doMute -> // vss.updateVolumeGroupIndex synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { final VolumeStreamState streamState = getVssForStreamOrDefault(streamAlias); // if unmuting causes a change, it was muted wasMuted = streamState.mute(false, "onUnmuteStreamOnSingleVolDevice"); @@ -4455,7 +4461,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#getVolumeGroupVolumeIndex(int) */ public int getVolumeGroupVolumeIndex(int groupId) { super.getVolumeGroupVolumeIndex_enforcePermission(); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (sVolumeGroupStates.indexOfKey(groupId) < 0) { Log.e(TAG, "No volume group for id " + groupId); return 0; @@ -4472,7 +4478,7 @@ public class AudioService extends IAudioService.Stub MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING }) public int getVolumeGroupMaxVolumeIndex(int groupId) { super.getVolumeGroupMaxVolumeIndex_enforcePermission(); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (sVolumeGroupStates.indexOfKey(groupId) < 0) { Log.e(TAG, "No volume group for id " + groupId); return 0; @@ -4487,7 +4493,7 @@ public class AudioService extends IAudioService.Stub MODIFY_AUDIO_SETTINGS_PRIVILEGED, MODIFY_AUDIO_ROUTING }) public int getVolumeGroupMinVolumeIndex(int groupId) { super.getVolumeGroupMinVolumeIndex_enforcePermission(); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (sVolumeGroupStates.indexOfKey(groupId) < 0) { Log.e(TAG, "No volume group for id " + groupId); return 0; @@ -4632,7 +4638,7 @@ public class AudioService extends IAudioService.Stub @android.annotation.EnforcePermission(QUERY_AUDIO_STATE) public int getLastAudibleVolumeForVolumeGroup(int groupId) { super.getLastAudibleVolumeForVolumeGroup_enforcePermission(); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (sVolumeGroupStates.indexOfKey(groupId) < 0) { Log.e(TAG, ": no volume group found for id " + groupId); return 0; @@ -4644,7 +4650,7 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#isVolumeGroupMuted(int) */ public boolean isVolumeGroupMuted(int groupId) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (sVolumeGroupStates.indexOfKey(groupId) < 0) { Log.e(TAG, ": no volume group found for id " + groupId); return false; @@ -4990,6 +4996,8 @@ public class AudioService extends IAudioService.Stub + cacheGetStreamMinMaxVolume()); pw.println("\tandroid.media.audio.Flags.cacheGetStreamVolume:" + cacheGetStreamVolume()); + pw.println("\tcom.android.media.audio.optimizeBtDeviceSwitch:" + + optimizeBtDeviceSwitch()); } private void dumpAudioMode(PrintWriter pw) { @@ -5470,7 +5478,7 @@ public class AudioService extends IAudioService.Stub } streamType = replaceBtScoStreamWithVoiceCall(streamType, "isStreamMute"); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { ensureValidStreamType(streamType); return getVssForStreamOrDefault(streamType).mIsMuted; } @@ -5651,7 +5659,7 @@ public class AudioService extends IAudioService.Stub } private int getStreamVolume(int streamType, int device) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { final VolumeStreamState vss = getVssForStreamOrDefault(streamType); int index = vss.getIndex(device); @@ -5695,7 +5703,7 @@ public class AudioService extends IAudioService.Stub vib.setMinVolumeIndex((vss.mIndexMin + 5) / 10); vib.setMaxVolumeIndex((vss.mIndexMax + 5) / 10); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { final int index; if (isFixedVolumeDevice(ada.getInternalType())) { index = (vss.mIndexMax + 5) / 10; @@ -6263,7 +6271,7 @@ public class AudioService extends IAudioService.Stub // ring and notifications volume should never be 0 when not silenced if (sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_RING || sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_NOTIFICATION) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { for (int i = 0; i < vss.mIndexMap.size(); i++) { int device = vss.mIndexMap.keyAt(i); int value = vss.mIndexMap.valueAt(i); @@ -7023,7 +7031,7 @@ public class AudioService extends IAudioService.Stub } streamState.readSettings(); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { // unmute stream that was muted but is not affect by mute anymore if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) && !isStreamMutedByRingerOrZenMode(streamType)) || mUseFixedVolume)) { @@ -8056,14 +8064,14 @@ public class AudioService extends IAudioService.Stub public Set<Integer> getDeviceSetForStream(int stream) { stream = replaceBtScoStreamWithVoiceCall(stream, "getDeviceSetForStream"); ensureValidStreamType(stream); - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { return getVssForStreamOrDefault(stream).observeDevicesForStream_syncVSS(true); } } private void onObserveDevicesForAllStreams(int skipStream) { synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { for (int stream = 0; stream < mStreamStates.size(); stream++) { final VolumeStreamState vss = mStreamStates.valueAt(stream); if (vss != null && vss.getStreamType() != skipStream) { @@ -8645,7 +8653,7 @@ public class AudioService extends IAudioService.Stub private void readVolumeGroupsSettings(boolean userSwitch) { synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (DEBUG_VOL) { Log.d(TAG, "readVolumeGroupsSettings userSwitch=" + userSwitch); } @@ -8703,7 +8711,7 @@ public class AudioService extends IAudioService.Stub // NOTE: Locking order for synchronized objects related to volume management: // 1 mSettingsLock - // 2 VolumeStreamState.class + // 2 mVolumeStateLock private class VolumeGroupState { private final AudioVolumeGroup mAudioVolumeGroup; private final SparseIntArray mIndexMap = new SparseIntArray(8); @@ -8797,7 +8805,7 @@ public class AudioService extends IAudioService.Stub * Mute/unmute the volume group * @param muted the new mute state */ - @GuardedBy("AudioService.VolumeStreamState.class") + @GuardedBy("AudioService.this.mVolumeStateLock") public boolean mute(boolean muted) { if (!isMutable()) { // Non mutable volume group @@ -8821,7 +8829,7 @@ public class AudioService extends IAudioService.Stub public void adjustVolume(int direction, int flags) { synchronized (mSettingsLock) { - synchronized (AudioService.VolumeStreamState.class) { + synchronized (mVolumeStateLock) { int device = getDeviceForVolume(); int previousIndex = getIndex(device); if (isMuteAdjust(direction) && !isMutable()) { @@ -8875,14 +8883,14 @@ public class AudioService extends IAudioService.Stub } public int getVolumeIndex() { - synchronized (AudioService.VolumeStreamState.class) { + synchronized (mVolumeStateLock) { return getIndex(getDeviceForVolume()); } } public void setVolumeIndex(int index, int flags) { synchronized (mSettingsLock) { - synchronized (AudioService.VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (mUseFixedVolume) { return; } @@ -8891,7 +8899,7 @@ public class AudioService extends IAudioService.Stub } } - @GuardedBy("AudioService.VolumeStreamState.class") + @GuardedBy("AudioService.this.mVolumeStateLock") private void setVolumeIndex(int index, int device, int flags) { // Update cache & persist (muted by volume 0 shall be persisted) updateVolumeIndex(index, device); @@ -8904,7 +8912,7 @@ public class AudioService extends IAudioService.Stub } } - @GuardedBy("AudioService.VolumeStreamState.class") + @GuardedBy("AudioService.this.mVolumeStateLock") public void updateVolumeIndex(int index, int device) { // Filter persistency if already exist and the index has not changed if (mIndexMap.indexOfKey(device) < 0 || mIndexMap.get(device) != index) { @@ -8922,7 +8930,7 @@ public class AudioService extends IAudioService.Stub } } - @GuardedBy("AudioService.VolumeStreamState.class") + @GuardedBy("AudioService.this.mVolumeStateLock") private void setVolumeIndexInt(int index, int device, int flags) { // Reflect mute state of corresponding stream by forcing index to 0 if muted // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted. @@ -8955,14 +8963,14 @@ public class AudioService extends IAudioService.Stub mAudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, muted, device); } - @GuardedBy("AudioService.VolumeStreamState.class") + @GuardedBy("AudioService.this.mVolumeStateLock") private int getIndex(int device) { int index = mIndexMap.get(device, -1); // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT return (index != -1) ? index : mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT); } - @GuardedBy("AudioService.VolumeStreamState.class") + @GuardedBy("AudioService.this.mVolumeStateLock") private boolean hasIndexForDevice(int device) { return (mIndexMap.get(device, -1) != -1); } @@ -8989,7 +8997,7 @@ public class AudioService extends IAudioService.Stub public void applyAllVolumes(boolean userSwitch) { String caller = "from vgs"; - synchronized (AudioService.VolumeStreamState.class) { + synchronized (mVolumeStateLock) { // apply device specific volumes first for (int i = 0; i < mIndexMap.size(); i++) { int device = mIndexMap.keyAt(i); @@ -9092,25 +9100,27 @@ public class AudioService extends IAudioService.Stub if (mUseFixedVolume || mHasValidStreamType) { return; } - if (DEBUG_VOL) { - Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group " - + mAudioVolumeGroup.name() - + ", device " + AudioSystem.getOutputDeviceName(device) - + " and User=" + getCurrentUserId() - + " mSettingName: " + mSettingName); - } + synchronized (mVolumeStateLock) { + if (DEBUG_VOL) { + Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + + " for group " + mAudioVolumeGroup.name() + + ", device " + AudioSystem.getOutputDeviceName(device) + + " and User=" + getCurrentUserId() + + " mSettingName: " + mSettingName); + } - boolean success = mSettings.putSystemIntForUser(mContentResolver, - getSettingNameForDevice(device), - getIndex(device), - getVolumePersistenceUserId()); - if (!success) { - Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name()); + boolean success = mSettings.putSystemIntForUser(mContentResolver, + getSettingNameForDevice(device), + getIndex(device), + getVolumePersistenceUserId()); + if (!success) { + Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name()); + } } } public void readSettings() { - synchronized (AudioService.VolumeStreamState.class) { + synchronized (mVolumeStateLock) { // force maximum volume on all streams if fixed volume property is set if (mUseFixedVolume) { mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax); @@ -9144,7 +9154,7 @@ public class AudioService extends IAudioService.Stub } } - @GuardedBy("AudioService.VolumeStreamState.class") + @GuardedBy("AudioService.this.mVolumeStateLock") private int getValidIndex(int index) { if (index < mIndexMin) { return mIndexMin; @@ -9218,7 +9228,7 @@ public class AudioService extends IAudioService.Stub // 1 mScoclient OR mSafeMediaVolumeState // 2 mSetModeLock // 3 mSettingsLock - // 4 VolumeStreamState.class + // 4 mVolumeStateLock /*package*/ class VolumeStreamState { private final int mStreamType; private VolumeGroupState mVolumeGroupState = null; @@ -9427,7 +9437,7 @@ public class AudioService extends IAudioService.Stub * * This is a reference to the local list, do not modify. */ - @GuardedBy("VolumeStreamState.class") + @GuardedBy("mVolumeStateLock") @NonNull public Set<Integer> observeDevicesForStream_syncVSS( boolean checkOthers) { @@ -9495,7 +9505,7 @@ public class AudioService extends IAudioService.Stub public void readSettings() { synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { // force maximum volume on all streams if fixed volume property is set if (mUseFixedVolume) { mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax); @@ -9515,7 +9525,7 @@ public class AudioService extends IAudioService.Stub } } } - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { for (int device : AudioSystem.DEVICE_OUT_ALL_SET) { // retrieve current volume for device @@ -9548,7 +9558,7 @@ public class AudioService extends IAudioService.Stub * will send the non-zero index together with muted state. Otherwise, index 0 will be sent * to native for signalising a muted stream. **/ - @GuardedBy("VolumeStreamState.class") + @GuardedBy("mVolumeStateLock") private void setStreamVolumeIndex(int index, int device) { // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted. // This allows RX path muting by the audio HAL only when explicitly muted but not when @@ -9570,8 +9580,8 @@ public class AudioService extends IAudioService.Stub mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, muted, device); } - // must be called while synchronized VolumeStreamState.class - @GuardedBy("VolumeStreamState.class") + // must be called while synchronized mVolumeStateLock + @GuardedBy("mVolumeStateLock") /*package*/ void applyDeviceVolume_syncVSS(int device) { int index; if (isFullyMuted() && !ringMyCar()) { @@ -9597,7 +9607,7 @@ public class AudioService extends IAudioService.Stub } public void applyAllVolumes() { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { // apply device specific volumes first int index; boolean isAbsoluteVolume = false; @@ -9659,7 +9669,7 @@ public class AudioService extends IAudioService.Stub final boolean isCurrentDevice; final StringBuilder aliasStreamIndexes = new StringBuilder(); synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { oldIndex = getIndex(device); index = getValidIndex(index, hasModifyAudioSettings); // for STREAM_SYSTEM_ENFORCED, do not sync aliased streams on the enforced index @@ -9708,76 +9718,82 @@ public class AudioService extends IAudioService.Stub } } } - } - } - if (changed) { - // If associated to volume group, update group cache - updateVolumeGroupIndex(device, /* forceMuteState= */ false); - - oldIndex = (oldIndex + 5) / 10; - index = (index + 5) / 10; - // log base stream changes to the event log - if (sStreamVolumeAlias.get(mStreamType, /*valueIfKeyNotFound=*/-1) == mStreamType) { - if (caller == null) { - Log.w(TAG, "No caller for volume_changed event", new Throwable()); - } - EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10, - caller); - } - // fire changed intents for all streams, but only when the device it changed on - // is the current device - if ((index != oldIndex) && isCurrentDevice) { - // for single volume devices, only send the volume change broadcast - // on the alias stream - final int streamAlias = sStreamVolumeAlias.get( - mStreamType, /*valueIfKeyNotFound=*/-1); - if (!mIsSingleVolume || streamAlias == mStreamType) { - mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); - mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, - oldIndex); - int extraStreamType = mStreamType; - // TODO: remove this when deprecating STREAM_BLUETOOTH_SCO - if (isStreamBluetoothSco(mStreamType)) { - mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, - AudioSystem.STREAM_BLUETOOTH_SCO); - extraStreamType = AudioSystem.STREAM_BLUETOOTH_SCO; - } else { - mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, - mStreamType); - } - mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS, - streamAlias); - - if (mStreamType == streamAlias) { - String aliasStreamIndexesString = ""; - if (!aliasStreamIndexes.isEmpty()) { - aliasStreamIndexesString = - " aliased streams: " + aliasStreamIndexes; - } - AudioService.sVolumeLogger.enqueue(new VolChangedBroadcastEvent( - extraStreamType, aliasStreamIndexesString, index, oldIndex)); - if (extraStreamType != mStreamType) { - AudioService.sVolumeLogger.enqueue(new VolChangedBroadcastEvent( - mStreamType, aliasStreamIndexesString, index, oldIndex)); + if (changed) { + // If associated to volume group, update group cache + updateVolumeGroupIndex(device, /* forceMuteState= */ false); + + oldIndex = (oldIndex + 5) / 10; + index = (index + 5) / 10; + // log base stream changes to the event log + if (sStreamVolumeAlias.get(mStreamType, /*valueIfKeyNotFound=*/-1) + == mStreamType) { + if (caller == null) { + Log.w(TAG, "No caller for volume_changed event", new Throwable()); } + EventLogTags.writeVolumeChanged( + mStreamType, oldIndex, index, mIndexMax / 10, caller); } - sendBroadcastToAll(mVolumeChanged, mVolumeChangedOptions); - if (extraStreamType != mStreamType) { - // send multiple intents in case we merged voice call and bt sco streams - mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, - mStreamType); - // do not use the options in thid case which could discard - // the previous intent - sendBroadcastToAll(mVolumeChanged, null); + // fire changed intents for all streams, but only when the device it changed + // on + // is the current device + if ((index != oldIndex) && isCurrentDevice) { + // for single volume devices, only send the volume change broadcast + // on the alias stream + final int streamAlias = + sStreamVolumeAlias.get(mStreamType, /*valueIfKeyNotFound=*/-1); + if (!mIsSingleVolume || streamAlias == mStreamType) { + mVolumeChanged.putExtra( + AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); + mVolumeChanged.putExtra( + AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); + int extraStreamType = mStreamType; + // TODO: remove this when deprecating STREAM_BLUETOOTH_SCO + if (isStreamBluetoothSco(mStreamType)) { + mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, + AudioSystem.STREAM_BLUETOOTH_SCO); + extraStreamType = AudioSystem.STREAM_BLUETOOTH_SCO; + } else { + mVolumeChanged.putExtra( + AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType); + } + mVolumeChanged.putExtra( + AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS, streamAlias); + + if (mStreamType == streamAlias) { + String aliasStreamIndexesString = ""; + if (!aliasStreamIndexes.isEmpty()) { + aliasStreamIndexesString = + " aliased streams: " + aliasStreamIndexes; + } + AudioService.sVolumeLogger.enqueue( + new VolChangedBroadcastEvent(extraStreamType, + aliasStreamIndexesString, index, oldIndex)); + if (extraStreamType != mStreamType) { + AudioService.sVolumeLogger.enqueue( + new VolChangedBroadcastEvent(mStreamType, + aliasStreamIndexesString, index, oldIndex)); + } + } + sendBroadcastToAll(mVolumeChanged, mVolumeChangedOptions); + if (extraStreamType != mStreamType) { + // send multiple intents in case we merged voice call and bt sco + // streams + mVolumeChanged.putExtra( + AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType); + // do not use the options in thid case which could discard + // the previous intent + sendBroadcastToAll(mVolumeChanged, null); + } + } } } + return changed; } } - return changed; } public int getIndex(int device) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { int index = mIndexMap.get(device, -1); if (index == -1) { // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT @@ -9788,7 +9804,7 @@ public class AudioService extends IAudioService.Stub } public @NonNull VolumeInfo getVolumeInfo(int device) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { int index = mIndexMap.get(device, -1); if (index == -1) { // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT @@ -9805,7 +9821,7 @@ public class AudioService extends IAudioService.Stub } public boolean hasIndexForDevice(int device) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { return (mIndexMap.get(device, -1) != -1); } } @@ -9837,8 +9853,8 @@ public class AudioService extends IAudioService.Stub * @param srcStream * @param caller */ - // must be sync'd on mSettingsLock before VolumeStreamState.class - @GuardedBy("VolumeStreamState.class") + // must be sync'd on mSettingsLock before mVolumeStateLock + @GuardedBy("mVolumeStateLock") public void setAllIndexes(VolumeStreamState srcStream, String caller) { if (srcStream == null || mStreamType == srcStream.mStreamType) { return; @@ -9862,8 +9878,8 @@ public class AudioService extends IAudioService.Stub } } - // must be sync'd on mSettingsLock before VolumeStreamState.class - @GuardedBy("VolumeStreamState.class") + // must be sync'd on mSettingsLock before mVolumeStateLock + @GuardedBy("mVolumeStateLock") public void setAllIndexesToMax() { for (int i = 0; i < mIndexMap.size(); i++) { mIndexMap.put(mIndexMap.keyAt(i), mIndexMax); @@ -9876,7 +9892,7 @@ public class AudioService extends IAudioService.Stub // vss.setIndex which grabs this lock after VSS.class. Locking order needs to be // preserved synchronized (mSettingsLock) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (mVolumeGroupState != null) { int groupIndex = (getIndex(device) + 5) / 10; if (DEBUG_VOL) { @@ -9908,7 +9924,7 @@ public class AudioService extends IAudioService.Stub */ public boolean mute(boolean state, String source) { boolean changed = false; - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { changed = mute(state, true, source); } if (changed) { @@ -9924,7 +9940,7 @@ public class AudioService extends IAudioService.Stub */ public boolean muteInternally(boolean state) { boolean changed = false; - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { if (state != mIsMutedInternally) { changed = true; mIsMutedInternally = state; @@ -9939,7 +9955,7 @@ public class AudioService extends IAudioService.Stub return changed; } - @GuardedBy("VolumeStreamState.class") + @GuardedBy("mVolumeStateLock") public boolean isFullyMuted() { return mIsMuted || mIsMutedInternally; } @@ -9960,7 +9976,7 @@ public class AudioService extends IAudioService.Stub */ public boolean mute(boolean state, boolean apply, String src) { boolean changed; - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { changed = state != mIsMuted; if (changed) { sMuteLogger.enqueue( @@ -9994,7 +10010,7 @@ public class AudioService extends IAudioService.Stub } public void doMute() { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { // If associated to volume group, update group cache updateVolumeGroupIndex(getDeviceForStream(mStreamType), /* forceMuteState= */true); @@ -10015,7 +10031,7 @@ public class AudioService extends IAudioService.Stub } public void checkFixedVolumeDevices() { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { // ignore settings for fixed volume devices: volume should always be at max or 0 if (sStreamVolumeAlias.get(mStreamType) == AudioSystem.STREAM_MUSIC) { for (int i = 0; i < mIndexMap.size(); i++) { @@ -10186,8 +10202,7 @@ public class AudioService extends IAudioService.Stub } /*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) { - - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { sendMsg(mAudioHandler, SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION, SENDMSG_QUEUE, device, (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device) || AudioSystem.isLeAudioDeviceType(device) ? 1 : 0), @@ -12191,7 +12206,7 @@ public class AudioService extends IAudioService.Stub mCameraSoundForced = cameraSoundForced; if (cameraSoundForcedChanged) { if (!mIsSingleVolume) { - synchronized (VolumeStreamState.class) { + synchronized (mVolumeStateLock) { final VolumeStreamState s = getVssForStreamOrDefault( AudioSystem.STREAM_SYSTEM_ENFORCED); if (cameraSoundForced) { diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index e86c34cab88a..a6267c156fb3 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -367,9 +367,9 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, * @return */ public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state, - int codecFormat) { + int codecFormat, boolean deviceSwitch) { invalidateRoutingCache(); - return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat); + return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat, deviceSwitch); } /** diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 922116999bc7..844e3524384d 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -26,6 +26,8 @@ import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER; import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_UNKNOWN; import static android.media.AudioManager.AUDIO_DEVICE_CATEGORY_WATCH; +import static com.android.media.audio.Flags.optimizeBtDeviceSwitch; + import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothA2dp; @@ -393,8 +395,11 @@ public class BtHelper { + "received with null profile proxy for device: " + btDevice)).printLog(TAG)); return; + } - onSetBtScoActiveDevice(btDevice); + boolean deviceSwitch = optimizeBtDeviceSwitch() + && btDevice != null && mBluetoothHeadsetDevice != null; + onSetBtScoActiveDevice(btDevice, deviceSwitch); } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); onScoAudioStateChanged(btState); @@ -814,7 +819,7 @@ public class BtHelper { if (device == null) { continue; } - onSetBtScoActiveDevice(device); + onSetBtScoActiveDevice(device, false /*deviceSwitch*/); } } else { Log.e(TAG, "onHeadsetProfileConnected: Null BluetoothAdapter"); @@ -907,7 +912,8 @@ public class BtHelper { } @GuardedBy("mDeviceBroker.mDeviceStateLock") - private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) { + private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive, + boolean deviceSwitch) { if (btDevice == null) { return true; } @@ -919,12 +925,12 @@ public class BtHelper { if (isActive) { audioDevice = btHeadsetDeviceToAudioDevice(btDevice); result = mDeviceBroker.handleDeviceConnection( - audioDevice, true /*connect*/, btDevice); + audioDevice, true /*connect*/, btDevice, false /*deviceSwitch*/); } else { AudioDeviceAttributes ada = mResolvedScoAudioDevices.get(btDevice); if (ada != null) { result = mDeviceBroker.handleDeviceConnection( - ada, false /*connect*/, btDevice); + ada, false /*connect*/, btDevice, deviceSwitch); } else { // Disconnect all possible audio device types if the disconnected device type is // unknown @@ -935,7 +941,8 @@ public class BtHelper { }; for (int outDeviceType : outDeviceTypes) { result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes( - outDeviceType, address, name), false /*connect*/, btDevice); + outDeviceType, address, name), false /*connect*/, btDevice, + deviceSwitch); } } } @@ -944,7 +951,7 @@ public class BtHelper { // handleDeviceConnection() && result to make sure the method get executed result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes( inDevice, address, name), - isActive, btDevice) && result; + isActive, btDevice, deviceSwitch) && result; if (result) { if (isActive) { mResolvedScoAudioDevices.put(btDevice, audioDevice); @@ -961,18 +968,18 @@ public class BtHelper { } @GuardedBy("mDeviceBroker.mDeviceStateLock") - /*package */ void onSetBtScoActiveDevice(BluetoothDevice btDevice) { + /*package */ void onSetBtScoActiveDevice(BluetoothDevice btDevice, boolean deviceSwitch) { Log.i(TAG, "onSetBtScoActiveDevice: " + getAnonymizedAddress(mBluetoothHeadsetDevice) - + " -> " + getAnonymizedAddress(btDevice)); + + " -> " + getAnonymizedAddress(btDevice) + ", deviceSwitch: " + deviceSwitch); final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice; if (Objects.equals(btDevice, previousActiveDevice)) { return; } - if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) { + if (!handleBtScoActiveDeviceChange(previousActiveDevice, false, deviceSwitch)) { Log.w(TAG, "onSetBtScoActiveDevice() failed to remove previous device " + getAnonymizedAddress(previousActiveDevice)); } - if (!handleBtScoActiveDeviceChange(btDevice, true)) { + if (!handleBtScoActiveDeviceChange(btDevice, true, false /*deviceSwitch*/)) { Log.e(TAG, "onSetBtScoActiveDevice() failed to add new device " + getAnonymizedAddress(btDevice)); // set mBluetoothHeadsetDevice to null when failing to add new device diff --git a/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java index 000ee5446962..9f364677705e 100644 --- a/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java +++ b/services/core/java/com/android/server/biometrics/BiometricCameraManagerImpl.java @@ -20,12 +20,16 @@ import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; import android.annotation.NonNull; import android.hardware.SensorPrivacyManager; +import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraManager; +import android.util.Log; import java.util.concurrent.ConcurrentHashMap; public class BiometricCameraManagerImpl implements BiometricCameraManager { + private static final String TAG = "BiometricCameraManager"; + private final CameraManager mCameraManager; private final SensorPrivacyManager mSensorPrivacyManager; private final ConcurrentHashMap<String, Boolean> mIsCameraAvailable = new ConcurrentHashMap<>(); @@ -52,12 +56,18 @@ public class BiometricCameraManagerImpl implements BiometricCameraManager { @Override public boolean isAnyCameraUnavailable() { - for (String cameraId : mIsCameraAvailable.keySet()) { - if (!mIsCameraAvailable.get(cameraId)) { - return true; + try { + for (String cameraId : mCameraManager.getCameraIdList()) { + if (!mIsCameraAvailable.getOrDefault(cameraId, true)) { + return true; + } } + return false; + } catch (CameraAccessException e) { + Log.e(TAG, "Camera exception thrown when trying to determine availability: ", e); + //If face HAL is unable to get access to a camera, it will return an error. + return false; } - return false; } @Override diff --git a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java index d412277d2605..f5284a3ed589 100644 --- a/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java +++ b/services/core/java/com/android/server/companion/virtual/VirtualDeviceManagerInternal.java @@ -211,4 +211,20 @@ public abstract class VirtualDeviceManagerInternal { */ public abstract @NonNull VirtualDeviceManager.VirtualDevice createVirtualDevice( @NonNull VirtualDeviceParams params); + + /** + * Returns the details of the virtual device with the given ID, if any. + * + * <p>The returned object is a read-only representation of the virtual device that expose its + * properties.</p> + * + * <p>Note that if the virtual device is closed and becomes invalid, the returned object will + * not be updated and may contain stale values. Use a {@link VirtualDeviceListener} for real + * time updates of the availability of virtual devices.</p> + * + * @return the virtual device with the requested ID, or {@code null} if no such device exists or + * it has already been closed. + */ + @Nullable + public abstract VirtualDevice getVirtualDevice(int deviceId); } diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 88f5c81231b8..c41b8db1ce75 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -333,7 +333,7 @@ public class AutomaticBrightnessController { int ambientLightHorizonLong, float userLux, float userNits, DisplayManagerFlags displayManagerFlags) { mInjector = injector; - mClock = injector.createClock(displayManagerFlags.offloadControlsDozeAutoBrightness()); + mClock = injector.createClock(); mContext = context; mCallbacks = callbacks; mSensorManager = sensorManager; @@ -1402,8 +1402,7 @@ public class AutomaticBrightnessController { public void onSensorChanged(SensorEvent event) { if (mLightSensorEnabled) { // The time received from the sensor is in nano seconds, hence changing it to ms - final long time = (mDisplayManagerFlags.offloadControlsDozeAutoBrightness()) - ? TimeUnit.NANOSECONDS.toMillis(event.timestamp) : mClock.uptimeMillis(); + final long time = TimeUnit.NANOSECONDS.toMillis(event.timestamp); final float lux = event.values[0]; handleLightSensorEvent(time, lux); } @@ -1616,20 +1615,13 @@ public class AutomaticBrightnessController { } private static class RealClock implements Clock { - private final boolean mOffloadControlsDozeBrightness; - - RealClock(boolean offloadControlsDozeBrightness) { - mOffloadControlsDozeBrightness = offloadControlsDozeBrightness; - } - @Override public long uptimeMillis() { return SystemClock.uptimeMillis(); } public long getSensorEventScaleTime() { - return (mOffloadControlsDozeBrightness) - ? SystemClock.elapsedRealtime() : uptimeMillis(); + return SystemClock.elapsedRealtime(); } } @@ -1638,8 +1630,8 @@ public class AutomaticBrightnessController { return BackgroundThread.getHandler(); } - Clock createClock(boolean offloadControlsDozeBrightness) { - return new RealClock(offloadControlsDozeBrightness); + Clock createClock() { + return new RealClock(); } } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 0aa7227ac7e6..258c95582e3a 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -812,7 +812,7 @@ public final class DisplayManagerService extends SystemService { handleMinimalPostProcessingAllowedSettingChange(); if (mFlags.isDisplayContentModeManagementEnabled()) { - updateMirrorBuiltInDisplaySettingLocked(); + updateMirrorBuiltInDisplaySettingLocked(/*shouldSendDisplayChangeEvent=*/ true); } final UserManager userManager = getUserManager(); @@ -868,7 +868,7 @@ public final class DisplayManagerService extends SystemService { updateHdrConversionModeSettingsLocked(); } if (mFlags.isDisplayContentModeManagementEnabled()) { - updateMirrorBuiltInDisplaySettingLocked(); + updateMirrorBuiltInDisplaySettingLocked(/*shouldSendDisplayChangeEvent=*/ false); } } @@ -1237,8 +1237,11 @@ public final class DisplayManagerService extends SystemService { } if (Settings.Secure.getUriFor(MIRROR_BUILT_IN_DISPLAY).equals(uri)) { - if (mFlags.isDisplayContentModeManagementEnabled()) { - updateMirrorBuiltInDisplaySettingLocked(); + synchronized (mSyncRoot) { + if (mFlags.isDisplayContentModeManagementEnabled()) { + updateMirrorBuiltInDisplaySettingLocked(/*shouldSendDisplayChangeEvent=*/ + true); + } } return; } @@ -1258,18 +1261,19 @@ public final class DisplayManagerService extends SystemService { 1, UserHandle.USER_CURRENT) != 0); } - private void updateMirrorBuiltInDisplaySettingLocked() { - synchronized (mSyncRoot) { - ContentResolver resolver = mContext.getContentResolver(); - final boolean mirrorBuiltInDisplay = Settings.Secure.getIntForUser(resolver, - MIRROR_BUILT_IN_DISPLAY, 0, UserHandle.USER_CURRENT) != 0; - if (mMirrorBuiltInDisplay == mirrorBuiltInDisplay) { - return; - } - mMirrorBuiltInDisplay = mirrorBuiltInDisplay; - if (mFlags.isDisplayContentModeManagementEnabled()) { - mLogicalDisplayMapper.forEachLocked(this::updateCanHostTasksIfNeededLocked); - } + private void updateMirrorBuiltInDisplaySettingLocked(boolean shouldSendDisplayChangeEvent) { + ContentResolver resolver = mContext.getContentResolver(); + final boolean mirrorBuiltInDisplay = Settings.Secure.getIntForUser(resolver, + MIRROR_BUILT_IN_DISPLAY, 0, UserHandle.USER_CURRENT) != 0; + if (mMirrorBuiltInDisplay == mirrorBuiltInDisplay) { + return; + } + mMirrorBuiltInDisplay = mirrorBuiltInDisplay; + if (mFlags.isDisplayContentModeManagementEnabled()) { + mLogicalDisplayMapper.forEachLocked(logicalDisplay -> { + updateCanHostTasksIfNeededLocked(logicalDisplay, + shouldSendDisplayChangeEvent); + }); } } @@ -2380,7 +2384,7 @@ public final class DisplayManagerService extends SystemService { new BrightnessPair(brightnessDefault, brightnessDefault)); if (mFlags.isDisplayContentModeManagementEnabled()) { - updateCanHostTasksIfNeededLocked(display); + updateCanHostTasksIfNeededLocked(display, /*shouldSendDisplayChangeEvent=*/ false); } DisplayManagerGlobal.invalidateLocalDisplayInfoCaches(); @@ -2614,7 +2618,8 @@ public final class DisplayManagerService extends SystemService { // Blank or unblank the display immediately to match the state requested // by the display power controller (if known). DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); - if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { + if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0 + || android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) { final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); if (display == null) { return null; @@ -2702,8 +2707,9 @@ public final class DisplayManagerService extends SystemService { } } - private void updateCanHostTasksIfNeededLocked(LogicalDisplay display) { - if (display.setCanHostTasksLocked(!mMirrorBuiltInDisplay)) { + private void updateCanHostTasksIfNeededLocked(LogicalDisplay display, + boolean shouldSendDisplayChangeEvent) { + if (display.setCanHostTasksLocked(!mMirrorBuiltInDisplay) && shouldSendDisplayChangeEvent) { sendDisplayEventIfEnabledLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_BASIC_CHANGED); } @@ -5574,7 +5580,9 @@ public final class DisplayManagerService extends SystemService { final DisplayDevice displayDevice = mLogicalDisplayMapper.getDisplayLocked( id).getPrimaryDisplayDeviceLocked(); final int flags = displayDevice.getDisplayDeviceInfoLocked().flags; - if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { + if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0 + || android.companion.virtualdevice.flags.Flags + .correctVirtualDisplayPowerState()) { final DisplayPowerController displayPowerController = mDisplayPowerControllers.get(id); if (displayPowerController != null) { diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 872f33484951..f4daf8761e9b 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -890,10 +890,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { // still need to let WindowManager know so it can update its own internal state for // things like display cutouts. display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo); - if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) { - logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_BASIC_CHANGED - | LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED; + if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo, + /* compareOnlyBasicChanges */ true)) { + logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_BASIC_CHANGED; } + logicalDisplayEventMask + |= updateAndGetMaskForDisplayPropertyChanges(mTempNonOverrideDisplayInfo); } mLogicalDisplaysToUpdate.put(displayId, logicalDisplayEventMask); mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED); diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 4779b690adfb..e7939bb50ece 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -371,7 +371,15 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mCallback = callback; mProjection = projection; mMediaProjectionCallback = mediaProjectionCallback; - mDisplayState = Display.STATE_ON; + if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) { + // The display's power state depends on the power state of the state of its + // display / power group, which we don't know here. Initializing to UNKNOWN allows + // the first call to requestDisplayStateLocked() to set the correct state. + // This also triggers VirtualDisplay.Callback to tell the owner the initial state. + mDisplayState = Display.STATE_UNKNOWN; + } else { + mDisplayState = Display.STATE_ON; + } mPendingChanges |= PENDING_SURFACE_CHANGE; mDisplayIdToMirror = virtualDisplayConfig.getDisplayIdToMirror(); mIsWindowManagerMirroring = virtualDisplayConfig.isWindowManagerMirroringEnabled(); @@ -564,14 +572,23 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.yDpi = mDensityDpi; mInfo.presentationDeadlineNanos = 1000000000L / (int) getRefreshRate(); // 1 frame mInfo.flags = 0; - if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { - mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE - | DisplayDeviceInfo.FLAG_NEVER_BLANK; - } - if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { - mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK; + if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) { + if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { + mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE; + } + if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) { + mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; + } } else { - mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; + if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) { + mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE + | DisplayDeviceInfo.FLAG_NEVER_BLANK; + } + if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) { + mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK; + } else { + mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY; + } } if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) { mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP; diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java index 2c6f37448735..6510441ba28f 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java @@ -291,8 +291,7 @@ public class DisplayBrightnessStrategySelector { void setAllowAutoBrightnessWhileDozing( DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) { mAllowAutoBrightnessWhileDozing = mAllowAutoBrightnessWhileDozingConfig; - if (mDisplayManagerFlags.offloadControlsDozeAutoBrightness() - && mDisplayManagerFlags.isDisplayOffloadEnabled() + if (mDisplayManagerFlags.isDisplayOffloadEnabled() && displayOffloadSession != null) { mAllowAutoBrightnessWhileDozing &= displayOffloadSession.allowAutoBrightnessInDoze(); } 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 4ff092d3d759..7cc178d5ff6c 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -156,11 +156,6 @@ public class DisplayManagerFlags { Flags.FLAG_DOZE_BRIGHTNESS_FLOAT, Flags::dozeBrightnessFloat); - private final FlagState mOffloadControlsDozeAutoBrightness = new FlagState( - Flags.FLAG_OFFLOAD_CONTROLS_DOZE_AUTO_BRIGHTNESS, - Flags::offloadControlsDozeAutoBrightness - ); - private final FlagState mPeakRefreshRatePhysicalLimit = new FlagState( Flags.FLAG_ENABLE_PEAK_REFRESH_RATE_PHYSICAL_LIMIT, Flags::enablePeakRefreshRatePhysicalLimit @@ -445,13 +440,6 @@ public class DisplayManagerFlags { return mDozeBrightnessFloat.isEnabled(); } - /** - * @return Whether DisplayOffload should control auto-brightness in doze - */ - public boolean offloadControlsDozeAutoBrightness() { - return mOffloadControlsDozeAutoBrightness.isEnabled(); - } - public boolean isPeakRefreshRatePhysicalLimitEnabled() { return mPeakRefreshRatePhysicalLimit.isEnabled(); } @@ -658,7 +646,6 @@ public class DisplayManagerFlags { pw.println(" " + mResolutionBackupRestore); pw.println(" " + mUseFusionProxSensor); pw.println(" " + mDozeBrightnessFloat); - pw.println(" " + mOffloadControlsDozeAutoBrightness); pw.println(" " + mPeakRefreshRatePhysicalLimit); pw.println(" " + mIgnoreAppPreferredRefreshRate); pw.println(" " + mSynthetic60hzModes); 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 fd34046dc336..a0064a9f5d1d 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 @@ -255,17 +255,6 @@ flag { } flag { - name: "offload_controls_doze_auto_brightness" - namespace: "display_manager" - description: "Allows the registered DisplayOffloader to control if auto-brightness is used in doze" - bug: "327392714" - is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "enable_peak_refresh_rate_physical_limit" namespace: "display_manager" description: "Flag for adding physical refresh rate limit if smooth display setting is on " diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index 7e8bb28b6a37..2af74f620c95 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -569,7 +569,8 @@ public final class DreamManagerService extends SystemService { } private void requestDreamInternal() { - if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()) { + if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront() + && !isDozingInternal()) { return; } diff --git a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java index 94842041af82..ab86433ca50d 100644 --- a/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java +++ b/services/core/java/com/android/server/hdmi/AudioDeviceVolumeManagerWrapper.java @@ -58,9 +58,9 @@ public interface AudioDeviceVolumeManagerWrapper { void setDeviceAbsoluteVolumeBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment); + @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener); /** * Wrapper for {@link AudioDeviceVolumeManager#setDeviceAbsoluteVolumeAdjustOnlyBehavior( @@ -69,7 +69,7 @@ public interface AudioDeviceVolumeManagerWrapper { void setDeviceAbsoluteVolumeAdjustOnlyBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment); + @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener); } diff --git a/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java index ff99ace38ef0..10cbb00d2398 100644 --- a/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java +++ b/services/core/java/com/android/server/hdmi/DefaultAudioDeviceVolumeManagerWrapper.java @@ -61,21 +61,21 @@ public class DefaultAudioDeviceVolumeManagerWrapper public void setDeviceAbsoluteVolumeBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { - mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeBehavior(device, volume, executor, - vclistener, handlesVolumeAdjustment); + @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener) { + mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeBehavior(device, volume, + handlesVolumeAdjustment, executor, vclistener); } @Override public void setDeviceAbsoluteVolumeAdjustOnlyBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { + @NonNull AudioDeviceVolumeManager.OnAudioDeviceVolumeChangedListener vclistener) { mAudioDeviceVolumeManager.setDeviceAbsoluteVolumeAdjustOnlyBehavior(device, volume, - executor, vclistener, handlesVolumeAdjustment); + handlesVolumeAdjustment, executor, vclistener); } } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 89f0d0edbf2b..6d973ac8d1b5 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -4798,15 +4798,15 @@ public class HdmiControlService extends SystemService { Slog.d(TAG, "Enabling absolute volume behavior"); for (AudioDeviceAttributes device : getAvbCapableAudioOutputDevices()) { getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeBehavior( - device, volumeInfo, mServiceThreadExecutor, - mAbsoluteVolumeChangedListener, true); + device, volumeInfo, true, mServiceThreadExecutor, + mAbsoluteVolumeChangedListener); } } else if (tv() != null) { Slog.d(TAG, "Enabling adjust-only absolute volume behavior"); for (AudioDeviceAttributes device : getAvbCapableAudioOutputDevices()) { getAudioDeviceVolumeManager().setDeviceAbsoluteVolumeAdjustOnlyBehavior( - device, volumeInfo, mServiceThreadExecutor, - mAbsoluteVolumeChangedListener, true); + device, volumeInfo, true, mServiceThreadExecutor, + mAbsoluteVolumeChangedListener); } } diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java index 977c029f3a29..d71c8a1056d9 100644 --- a/services/core/java/com/android/server/input/InputGestureManager.java +++ b/services/core/java/com/android/server/input/InputGestureManager.java @@ -146,11 +146,6 @@ final class InputGestureManager { KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL ), createKeyGesture( - KeyEvent.KEYCODE_N, - KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON, - KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES - ), - createKeyGesture( KeyEvent.KEYCODE_S, KeyEvent.META_META_ON, KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 0e37238bcb84..c2fecf283a34 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -143,6 +143,7 @@ import com.android.internal.policy.KeyInterceptionInfo; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; import com.android.server.DisplayThread; +import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.Watchdog; @@ -469,11 +470,13 @@ public class InputManagerService extends IInputManager.Stub static class Injector { private final Context mContext; private final Looper mLooper; + private final Looper mIoLooper; private final UEventManager mUEventManager; - Injector(Context context, Looper looper, UEventManager uEventManager) { + Injector(Context context, Looper looper, Looper ioLooper, UEventManager uEventManager) { mContext = context; mLooper = looper; + mIoLooper = ioLooper; mUEventManager = uEventManager; } @@ -485,6 +488,10 @@ public class InputManagerService extends IInputManager.Stub return mLooper; } + Looper getIoLooper() { + return mIoLooper; + } + UEventManager getUEventManager() { return mUEventManager; } @@ -505,8 +512,8 @@ public class InputManagerService extends IInputManager.Stub } public InputManagerService(Context context) { - this(new Injector(context, DisplayThread.get().getLooper(), new UEventManager() {}), - context.getSystemService(PermissionEnforcer.class)); + this(new Injector(context, DisplayThread.get().getLooper(), IoThread.get().getLooper(), + new UEventManager() {}), context.getSystemService(PermissionEnforcer.class)); } @VisibleForTesting @@ -532,7 +539,7 @@ public class InputManagerService extends IInputManager.Stub mStickyModifierStateController = new StickyModifierStateController(); mInputDataStore = new InputDataStore(); mKeyGestureController = new KeyGestureController(mContext, injector.getLooper(), - mInputDataStore); + injector.getIoLooper(), mInputDataStore); mKeyboardLedController = new KeyboardLedController(mContext, injector.getLooper(), mNative); mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper()); diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java index 5770a09e3b92..fba0b0453bfb 100644 --- a/services/core/java/com/android/server/input/KeyGestureController.java +++ b/services/core/java/com/android/server/input/KeyGestureController.java @@ -121,6 +121,7 @@ final class KeyGestureController { private final Context mContext; private final Handler mHandler; + private final Handler mIoHandler; private final int mSystemPid; private final KeyCombinationManager mKeyCombinationManager; private final SettingsObserver mSettingsObserver; @@ -171,9 +172,11 @@ final class KeyGestureController { private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled(); - KeyGestureController(Context context, Looper looper, InputDataStore inputDataStore) { + KeyGestureController(Context context, Looper looper, Looper ioLooper, + InputDataStore inputDataStore) { mContext = context; mHandler = new Handler(looper, this::handleMessage); + mIoHandler = new Handler(ioLooper, this::handleIoMessage); mSystemPid = Process.myPid(); mKeyGestureHandlerRecords = new TreeMap<>((p1, p2) -> { if (Objects.equals(p1, p2)) { @@ -458,7 +461,7 @@ final class KeyGestureController { userId = mCurrentUserId; } // Load the system user's input gestures. - mHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget(); + mIoHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget(); } public boolean interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { @@ -1032,7 +1035,7 @@ final class KeyGestureController { synchronized (mUserLock) { mCurrentUserId = userId; } - mHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget(); + mIoHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget(); } @MainThread @@ -1073,6 +1076,12 @@ final class KeyGestureController { AidlKeyGestureEvent event = (AidlKeyGestureEvent) msg.obj; notifyKeyGestureEvent(event); break; + } + return true; + } + + private boolean handleIoMessage(Message msg) { + switch (msg.what) { case MSG_PERSIST_CUSTOM_GESTURES: { final int userId = (Integer) msg.obj; persistInputGestures(userId); @@ -1083,7 +1092,6 @@ final class KeyGestureController { loadInputGestures(userId); break; } - } return true; } @@ -1144,7 +1152,7 @@ final class KeyGestureController { final int result = mInputGestureManager.addCustomInputGesture(userId, new InputGestureData(inputGestureData)); if (result == InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS) { - mHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); + mIoHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); } return result; } @@ -1156,7 +1164,7 @@ final class KeyGestureController { final int result = mInputGestureManager.removeCustomInputGesture(userId, new InputGestureData(inputGestureData)); if (result == InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS) { - mHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); + mIoHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); } return result; } @@ -1165,7 +1173,7 @@ final class KeyGestureController { public void removeAllCustomInputGestures(@UserIdInt int userId, @Nullable InputGestureData.Filter filter) { mInputGestureManager.removeAllCustomInputGestures(userId, filter); - mHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); + mIoHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget(); } @BinderThread diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 334e7b5240ce..dfdd9e54fe2e 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -365,7 +365,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. return mCurrentImeUserId; } - /** + /** * Figures out the target IME user ID associated with the given {@code displayId}. * * @param displayId the display ID to be queried about @@ -1332,8 +1332,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // Do not reset the default (current) IME when it is a 3rd-party IME String selectedMethodId = bindingController.getSelectedMethodId(); final InputMethodSettings settings = InputMethodSettingsRepository.get(userId); - if (selectedMethodId != null && settings.getMethodMap().get(selectedMethodId) != null - && !settings.getMethodMap().get(selectedMethodId).isSystem()) { + final InputMethodInfo selectedImi = settings.getMethodMap().get(selectedMethodId); + if (selectedImi != null && !selectedImi.isSystem()) { return; } final List<InputMethodInfo> suitableImes = InputMethodInfoUtils.getDefaultEnabledImes( @@ -3485,7 +3485,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. || (windowPerceptible != null && windowPerceptible == perceptible)) { return; } - mFocusedWindowPerceptible.put(windowToken, windowPerceptible); + mFocusedWindowPerceptible.put(windowToken, perceptible); updateSystemUiLocked(userId); } }); diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java index 2ea61171b9e1..1a29150cd40c 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java @@ -374,6 +374,34 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(mEndpointInfo).append(", "); + sb.append("package: ").append(mPackageName).append(", "); + synchronized (mWakeLock) { + sb.append("wakelock: ").append(mWakeLock); + } + synchronized (mOpenSessionLock) { + if (mSessionInfoMap.size() != 0) { + sb.append(System.lineSeparator()); + sb.append(" sessions: "); + sb.append(System.lineSeparator()); + } + for (int i = 0; i < mSessionInfoMap.size(); i++) { + int id = mSessionInfoMap.keyAt(i); + int count = i + 1; + sb.append( + " " + count + ". id=" + + id + + ", remote:" + + mSessionInfoMap.get(id).getRemoteEndpointInfo()); + sb.append(System.lineSeparator()); + } + } + return sb.toString(); + } + /** * Registers this endpoints with the Context Hub HAL. * diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java index 06aeb62a28b8..30bb8f3fa188 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java @@ -16,6 +16,7 @@ package com.android.server.location.contexthub; +import android.annotation.IntDef; import android.content.Context; import android.hardware.contexthub.ContextHubInfo; import android.hardware.contexthub.EndpointInfo; @@ -34,8 +35,11 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -105,6 +109,48 @@ import java.util.function.Consumer; /** The interface for endpoint communication (retrieved from HAL in init()) */ private IEndpointCommunication mHubInterface = null; + /* + * The list of previous registration records. + */ + private static final int NUM_CLIENT_RECORDS = 20; + private final ConcurrentLinkedEvictingDeque<RegistrationRecord> mRegistrationRecordDeque = + new ConcurrentLinkedEvictingDeque<>(NUM_CLIENT_RECORDS); + + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"ACTION_"}, + value = { + ACTION_REGISTERED, + ACTION_UNREGISTERED, + }) + public @interface Action {} + + public static final int ACTION_REGISTERED = 0; + public static final int ACTION_UNREGISTERED = 1; + + /** A container class to store a record of ContextHubEndpointBroker registrations. */ + private class RegistrationRecord { + private final String mBroker; + private final int mAction; + private final long mTimestamp; + + RegistrationRecord(String broker, @Action int action) { + mBroker = broker; + mAction = action; + mTimestamp = System.currentTimeMillis(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(ContextHubServiceUtil.formatDateFromTimestamp(mTimestamp)); + sb.append(" "); + sb.append(mAction == ACTION_REGISTERED ? "+ " : "- "); + sb.append(mBroker); + return sb.toString(); + } + } + /* package */ ContextHubEndpointManager( Context context, IContextHubWrapper contextHubProxy, @@ -228,6 +274,7 @@ import java.util.function.Consumer; return null; } + mRegistrationRecordDeque.add(new RegistrationRecord(broker.toString(), ACTION_REGISTERED)); Log.d(TAG, "Registered endpoint with ID = " + endpointId); return IContextHubEndpoint.Stub.asInterface(broker); } @@ -274,7 +321,11 @@ import java.util.function.Consumer; * @param endpointId The ID of the endpoint to unregister. */ /* package */ void unregisterEndpoint(long endpointId) { - mEndpointMap.remove(endpointId); + ContextHubEndpointBroker broker = mEndpointMap.remove(endpointId); + if (broker != null) { + mRegistrationRecordDeque.add( + new RegistrationRecord(broker.toString(), ACTION_UNREGISTERED)); + } } /** Invoked by the service when the Context Hub HAL restarts. */ @@ -366,6 +417,27 @@ import java.util.function.Consumer; } } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + int count = 1; + for (ContextHubEndpointBroker broker : mEndpointMap.values()) { + sb.append(count + ". " + broker); + sb.append(System.lineSeparator()); + count++; + } + + sb.append(System.lineSeparator()); + sb.append("Registration History:"); + sb.append(System.lineSeparator()); + Iterator<RegistrationRecord> it = mRegistrationRecordDeque.descendingIterator(); + while (it.hasNext()) { + sb.append(it.next()); + sb.append(System.lineSeparator()); + } + return sb.toString(); + } + /** * Invokes a callback for a session with matching ID. * diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java index 502a7aeba258..bf7351cb11db 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -1579,6 +1579,12 @@ public class ContextHubService extends IContextHubService.Stub { pw.println("=================== CLIENTS ===================="); pw.println(mClientManager); + if (mEndpointManager != null) { + pw.println(""); + pw.println("=================== ENDPOINTS ===================="); + pw.println(mEndpointManager); + } + pw.println(""); pw.println("=================== TRANSACTIONS ===================="); pw.println(mTransactionManager); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS index bb487fb52c9f..ebf7e6bed064 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS @@ -1,4 +1,3 @@ aseemk@google.com bozhu@google.com dementyev@google.com -robertberry@google.com diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java index 6c0035b82a86..f680ce722e81 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java @@ -514,11 +514,14 @@ interface NotificationRecordLogger { final int fsi_state; final boolean is_locked; final int age_in_minutes; + final boolean is_promoted_ongoing; + final boolean has_promotable_characteristics; @DurationMillisLong long post_duration_millis; // Not final; calculated at the end. NotificationReported(NotificationRecordPair p, NotificationReportedEvent eventType, int position, int buzzBeepBlink, InstanceId groupId) { + final Notification notification = p.r.getSbn().getNotification(); this.event_id = eventType.getId(); this.uid = p.r.getUid(); this.package_name = p.r.getSbn().getPackageName(); @@ -527,8 +530,8 @@ interface NotificationRecordLogger { this.channel_id_hash = p.getChannelIdHash(); this.group_id_hash = p.getGroupIdHash(); this.group_instance_id = (groupId == null) ? 0 : groupId.getId(); - this.is_group_summary = p.r.getSbn().getNotification().isGroupSummary(); - this.category = p.r.getSbn().getNotification().category; + this.is_group_summary = notification.isGroupSummary(); + this.category = notification.category; this.style = p.getStyle(); this.num_people = p.getNumPeople(); this.position = position; @@ -542,22 +545,18 @@ interface NotificationRecordLogger { this.assistant_ranking_score = p.r.getRankingScore(); this.is_ongoing = p.r.getSbn().isOngoing(); this.is_foreground_service = NotificationRecordLogger.isForegroundService(p.r); - this.timeout_millis = p.r.getSbn().getNotification().getTimeoutAfter(); + this.timeout_millis = notification.getTimeoutAfter(); this.is_non_dismissible = NotificationRecordLogger.isNonDismissible(p.r); - - final boolean hasFullScreenIntent = - p.r.getSbn().getNotification().fullScreenIntent != null; - - final boolean hasFsiRequestedButDeniedFlag = (p.r.getSbn().getNotification().flags - & Notification.FLAG_FSI_REQUESTED_BUT_DENIED) != 0; - + final boolean hasFullScreenIntent = notification.fullScreenIntent != null; + final boolean hasFsiRequestedButDeniedFlag = + (notification.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED) != 0; this.fsi_state = NotificationRecordLogger.getFsiState( hasFullScreenIntent, hasFsiRequestedButDeniedFlag, eventType); - this.is_locked = p.r.isLocked(); - this.age_in_minutes = NotificationRecordLogger.getAgeInMinutes( - p.r.getSbn().getPostTime(), p.r.getSbn().getNotification().getWhen()); + p.r.getSbn().getPostTime(), notification.getWhen()); + this.is_promoted_ongoing = notification.isPromotedOngoing(); + this.has_promotable_characteristics = notification.hasPromotableCharacteristics(); } } diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java index fc0a7764963e..e0e3fbaf49f1 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java @@ -78,7 +78,9 @@ class NotificationRecordLoggerImpl implements NotificationRecordLogger { notificationReported.post_duration_millis, notificationReported.fsi_state, notificationReported.is_locked, - notificationReported.age_in_minutes); + notificationReported.age_in_minutes, + notificationReported.is_promoted_ongoing, + notificationReported.has_promotable_characteristics); } @Override diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 0fc182f3f1bb..fff812c038e7 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -42,6 +42,7 @@ import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_P import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED; +import static com.android.server.notification.PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE; import static com.android.server.notification.PreferencesHelper.LockableAppFields.USER_LOCKED_PROMOTABLE; import android.annotation.FlaggedApi; @@ -286,7 +287,7 @@ public class PreferencesHelper implements RankingConfig { if (!TAG_RANKING.equals(tag)) return; final int xmlVersion = parser.getAttributeInt(null, ATT_VERSION, -1); - boolean upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE; + boolean upgradeForBubbles = xmlVersion >= XML_VERSION_BUBBLES_UPGRADE; boolean migrateToPermission = (xmlVersion < XML_VERSION_NOTIF_PERMISSION); if (mShowReviewPermissionsNotification && (xmlVersion < XML_VERSION_REVIEW_PERMISSIONS_NOTIFICATION)) { @@ -337,15 +338,19 @@ public class PreferencesHelper implements RankingConfig { } boolean skipWarningLogged = false; boolean skipGroupWarningLogged = false; - boolean hasSAWPermission = false; - if (upgradeForBubbles && uid != UNKNOWN_UID) { - hasSAWPermission = mAppOps.noteOpNoThrow( - OP_SYSTEM_ALERT_WINDOW, uid, name, null, - "check-notif-bubble") == AppOpsManager.MODE_ALLOWED; - } - int bubblePref = hasSAWPermission - ? BUBBLE_PREFERENCE_ALL - : parser.getAttributeInt(null, ATT_ALLOW_BUBBLE, DEFAULT_BUBBLE_PREFERENCE); + int bubblePref = parser.getAttributeInt(null, ATT_ALLOW_BUBBLE, + DEFAULT_BUBBLE_PREFERENCE); + boolean bubbleLocked = (parser.getAttributeInt(null, + ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS) & USER_LOCKED_BUBBLE) + != 0; + if (!bubbleLocked + && upgradeForBubbles + && uid != UNKNOWN_UID + && mAppOps.noteOpNoThrow(OP_SYSTEM_ALERT_WINDOW, uid, name, null, + "check-notif-bubble") == AppOpsManager.MODE_ALLOWED) { + // User hasn't changed bubble pref & the app has SAW, so allow all bubbles. + bubblePref = BUBBLE_PREFERENCE_ALL; + } int appImportance = parser.getAttributeInt(null, ATT_IMPORTANCE, DEFAULT_IMPORTANCE); // when data is loaded from disk it's loaded as USER_ALL, but restored data that diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index f7a4d3d9132c..889df512dd60 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -157,6 +157,12 @@ public class ZenModeHelper { static final int RULE_LIMIT_PER_PACKAGE = 100; private static final Duration DELETED_RULE_KEPT_FOR = Duration.ofDays(30); + /** + * Amount of time since last activation after which implicit rules that have never been + * customized by the user are automatically cleaned up. + */ + private static final Duration IMPLICIT_RULE_KEPT_FOR = Duration.ofDays(30); + private static final int MAX_ICON_RESOURCE_NAME_LENGTH = 1000; /** @@ -534,7 +540,7 @@ public class ZenModeHelper { ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID); if (sleepingRule != null && !sleepingRule.enabled - && sleepingRule.canBeUpdatedByApp() /* meaning it's not user-customized */) { + && !sleepingRule.isUserModified()) { config.automaticRules.remove(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID); } } @@ -864,7 +870,7 @@ public class ZenModeHelper { // We don't try to preserve system-owned rules because their conditionIds (used as // deletedRuleKey) are not stable. This is almost moot anyway because an app cannot // delete a system-owned rule. - if (origin == ORIGIN_APP && !ruleToRemove.canBeUpdatedByApp() + if (origin == ORIGIN_APP && ruleToRemove.isUserModified() && !PACKAGE_ANDROID.equals(ruleToRemove.pkg)) { String deletedKey = ZenModeConfig.deletedRuleKey(ruleToRemove); if (deletedKey != null) { @@ -1282,7 +1288,7 @@ public class ZenModeHelper { // * the request comes from an origin that can always update values, like the user, or // * the rule has not yet been user modified, and thus can be updated by the app. boolean updateValues = isNew || doesOriginAlwaysUpdateValues(origin) - || rule.canBeUpdatedByApp(); + || !rule.isUserModified(); // For all other values, if updates are not allowed, we discard the update. if (!updateValues) { @@ -1914,6 +1920,7 @@ public class ZenModeHelper { * <ul> * <li>Rule instances whose owner is not installed. * <li>Deleted rules that were deleted more than 30 days ago. + * <li>Implicit rules that haven't been used in 30 days (and have not been customized). * </ul> */ private void cleanUpZenRules() { @@ -1932,6 +1939,10 @@ public class ZenModeHelper { } } + if (Flags.modesUi() && Flags.modesCleanupImplicit()) { + deleteUnusedImplicitRules(newConfig.automaticRules); + } + if (!newConfig.equals(mConfig)) { setConfigLocked(newConfig, null, ORIGIN_SYSTEM, "cleanUpZenRules", Process.SYSTEM_UID); @@ -1957,6 +1968,29 @@ public class ZenModeHelper { } } + private void deleteUnusedImplicitRules(ArrayMap<String, ZenRule> ruleList) { + if (ruleList == null) { + return; + } + Instant deleteIfUnusedSince = mClock.instant().minus(IMPLICIT_RULE_KEPT_FOR); + + for (int i = ruleList.size() - 1; i >= 0; i--) { + ZenRule rule = ruleList.valueAt(i); + if (isImplicitRuleId(rule.id) && !rule.isUserModified()) { + if (rule.lastActivation == null) { + // This rule existed before we started tracking activation time. It *might* be + // in use. Set lastActivation=now so it has some time (IMPLICIT_RULE_KEPT_FOR) + // before being removed if truly unused. + rule.lastActivation = mClock.instant(); + } + + if (rule.lastActivation.isBefore(deleteIfUnusedSince)) { + ruleList.removeAt(i); + } + } + } + } + /** * @return a copy of the zen mode configuration */ @@ -2091,6 +2125,20 @@ public class ZenModeHelper { } } + // Update last activation for rules that are being activated. + if (Flags.modesUi() && Flags.modesCleanupImplicit()) { + Instant now = mClock.instant(); + if (!mConfig.isManualActive() && config.isManualActive()) { + config.manualRule.lastActivation = now; + } + for (ZenRule rule : config.automaticRules.values()) { + ZenRule previousRule = mConfig.automaticRules.get(rule.id); + if (rule.isActive() && (previousRule == null || !previousRule.isActive())) { + rule.lastActivation = now; + } + } + } + mConfig = config; dispatchOnConfigChanged(); updateAndApplyConsolidatedPolicyAndDeviceEffects(origin, reason); diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 15688c0f7366..28117470e7a3 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -204,6 +204,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; @@ -1023,6 +1024,7 @@ final class InstallPackageHelper { */ void installPackagesTraced(List<InstallRequest> requests, MoveInfo moveInfo) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); + boolean pendingForDexopt = false; boolean success = false; final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size()); final Map<String, Settings.VersionInfo> versionInfos = new ArrayMap<>(requests.size()); @@ -1036,17 +1038,41 @@ final class InstallPackageHelper { if (reconciledPackages == null) { return; } + if (renameAndUpdatePaths(requests)) { // rename before dexopt because art will encoded the path in the odex/vdex file if (Flags.improveInstallFreeze()) { - prepPerformDexoptIfNeeded(reconciledPackages); - } - if (commitInstallPackages(reconciledPackages)) { - success = true; + pendingForDexopt = true; + final Runnable actionsAfterDexopt = () -> + doPostDexopt(reconciledPackages, requests, + createdAppId, moveInfo, acquireTime); + prepPerformDexoptIfNeeded(reconciledPackages, actionsAfterDexopt); + } else { + if (commitInstallPackages(reconciledPackages)) { + success = true; + } } } } } finally { + if (!pendingForDexopt) { + completeInstallProcess(requests, createdAppId, success); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + doPostInstall(requests, moveInfo); + releaseWakeLock(acquireTime, requests.size()); + } + } + } + + void doPostDexopt(List<ReconciledPackage> reconciledPackages, + List<InstallRequest> requests, Map<String, Boolean> createdAppId, + MoveInfo moveInfo, long acquireTime) { + boolean success = false; + try { + if (commitInstallPackages(reconciledPackages)) { + success = true; + } + } finally { completeInstallProcess(requests, createdAppId, success); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); doPostInstall(requests, moveInfo); @@ -1123,7 +1149,7 @@ final class InstallPackageHelper { throws PackageManagerException { final int userId = installRequest.getUserId(); if (userId != UserHandle.USER_ALL && userId != UserHandle.USER_CURRENT - && !mPm.mUserManager.exists(userId)) { + && !ArrayUtils.contains(allUsers, userId)) { throw new PackageManagerException(PackageManagerException.INTERNAL_ERROR_MISSING_USER, "User " + userId + " doesn't exist or has been removed"); } @@ -1155,7 +1181,9 @@ final class InstallPackageHelper { } } - private void prepPerformDexoptIfNeeded(List<ReconciledPackage> reconciledPackages) { + private void prepPerformDexoptIfNeeded(List<ReconciledPackage> reconciledPackages, + Runnable actionsAfterDexopt) { + List<CompletableFuture<Void>> completableFutures = new ArrayList<>(); for (ReconciledPackage reconciledPkg : reconciledPackages) { final InstallRequest request = reconciledPkg.mInstallRequest; // prepare profiles @@ -1171,6 +1199,7 @@ final class InstallPackageHelper { mSharedLibraries.executeSharedLibrariesUpdate(request.getParsedPackage(), ps, null, null, reconciledPkg.mCollectedSharedLibraryInfos, allUsers); } + try (PackageManagerTracedLock installLock = mPm.mInstallLock.acquireLock()) { final int[] newUsers = getNewUsers(request, allUsers); // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088) @@ -1182,11 +1211,22 @@ final class InstallPackageHelper { } } catch (PackageManagerException e) { request.setError(e.error, e.getMessage()); - return; + break; } request.setKeepArtProfile(true); - // TODO(b/388159696): Use performDexoptIfNeededAsync. - DexOptHelper.performDexoptIfNeeded(request, mDexManager, null /* installLock */); + + CompletableFuture<Void> future = + DexOptHelper.performDexoptIfNeededAsync(request, mDexManager); + completableFutures.add(future); + } + + if (!completableFutures.isEmpty()) { + CompletableFuture<Void> allFutures = + CompletableFuture.allOf( + completableFutures.toArray(CompletableFuture[]::new)); + var unused = allFutures.thenRun(() -> mPm.mHandler.post(actionsAfterDexopt)); + } else { + actionsAfterDexopt.run(); } } @@ -2759,6 +2799,7 @@ final class InstallPackageHelper { | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); } + // run synchronous dexopt if the freeze improvement is not supported DexOptHelper.performDexoptIfNeeded( installRequest, mDexManager, mPm.mInstallLock.getRawLock()); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index e1fcc6650650..2d0bb258e89f 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -805,22 +805,20 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } - if (Flags.recoverabilityDetection()) { - if (params.rollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH - || params.rollbackImpactLevel - == PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) { - if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) { - throw new IllegalArgumentException( - "Can't set rollbackImpactLevel when rollback is not enabled"); - } - if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Setting rollbackImpactLevel requires the MANAGE_ROLLBACKS permission"); - } - } else if (params.rollbackImpactLevel < 0) { - throw new IllegalArgumentException("rollbackImpactLevel can't be negative."); + if (params.rollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH + || params.rollbackImpactLevel + == PackageManager.ROLLBACK_USER_IMPACT_ONLY_MANUAL) { + if ((params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) == 0) { + throw new IllegalArgumentException( + "Can't set rollbackImpactLevel when rollback is not enabled"); + } + if (mContext.checkCallingOrSelfPermission(Manifest.permission.MANAGE_ROLLBACKS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Setting rollbackImpactLevel requires the MANAGE_ROLLBACKS permission"); } + } else if (params.rollbackImpactLevel < 0) { + throw new IllegalArgumentException("rollbackImpactLevel can't be negative."); } boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 352985d5a023..136cb1259113 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -948,6 +948,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { break; case MSG_ON_NATIVE_LIBS_EXTRACTED: handleOnNativeLibsExtracted(); + break; } return true; diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index aa235c2258ac..cf598e89c988 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -3561,9 +3561,6 @@ class PackageManagerShellCommand extends ShellCommand { sessionParams.setEnableRollback(true, rollbackStrategy); break; case "--rollback-impact-level": - if (!Flags.recoverabilityDetection()) { - throw new IllegalArgumentException("Unknown option " + opt); - } int rollbackImpactLevel = Integer.parseInt(peekNextArg()); if (rollbackImpactLevel < PackageManager.ROLLBACK_USER_IMPACT_LOW || rollbackImpactLevel @@ -4775,11 +4772,9 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" --full: cause the app to be installed as a non-ephemeral full app"); pw.println(" --enable-rollback: enable rollbacks for the upgrade."); pw.println(" 0=restore (default), 1=wipe, 2=retain"); - if (Flags.recoverabilityDetection()) { - pw.println( - " --rollback-impact-level: set device impact required for rollback."); - pw.println(" 0=low (default), 1=high, 2=manual only"); - } + pw.println( + " --rollback-impact-level: set device impact required for rollback."); + pw.println(" 0=low (default), 1=high, 2=manual only"); pw.println(" --install-location: force the install location:"); pw.println(" 0=auto, 1=internal only, 2=prefer external"); pw.println(" --install-reason: indicates why the app is being installed:"); diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java index 045d4db0a1f1..346327d1fa74 100644 --- a/services/core/java/com/android/server/pm/ShortcutLauncher.java +++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java @@ -453,7 +453,7 @@ class ShortcutLauncher extends ShortcutPackageItem { @Override protected File getShortcutPackageItemFile() { final File path = new File(mShortcutUser.mService.injectUserDataPath( - mShortcutUser.getUserId()), ShortcutUser.DIRECTORY_LUANCHERS); + mShortcutUser.getUserId()), ShortcutUser.DIRECTORY_LAUNCHERS); // Package user id and owner id can have different values for ShortcutLaunchers. Adding // user Id to the file name to create a unique path. Owner id is used in the root path. final String fileName = getPackageName() + getPackageUserId() + ".xml"; diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 373c1ed3c386..d3513053caf3 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -16,7 +16,9 @@ package com.android.server.pm; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; -import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; + +import static com.android.server.pm.ShortcutUser.DIRECTORY_LAUNCHERS; +import static com.android.server.pm.ShortcutUser.DIRECTORY_PACKAGES; import android.Manifest.permission; import android.annotation.IntDef; @@ -94,7 +96,6 @@ import android.os.ShellCommand; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; -import android.provider.DeviceConfig; import android.text.TextUtils; import android.text.format.TimeMigrationUtils; import android.util.ArraySet; @@ -112,7 +113,6 @@ import android.view.IWindowManager; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; @@ -155,7 +155,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.regex.Pattern; -import java.util.stream.Collectors; /** * TODO: @@ -171,7 +170,7 @@ public class ShortcutService extends IShortcutService.Stub { static final boolean DEBUG = false; // STOPSHIP if true static final boolean DEBUG_LOAD = false; // STOPSHIP if true static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true - static final boolean DEBUG_REBOOT = Build.IS_DEBUGGABLE; + static final boolean DEBUG_REBOOT = false; // STOPSHIP if true @VisibleForTesting static final long DEFAULT_RESET_INTERVAL_SEC = 24 * 60 * 60; // 1 day @@ -292,7 +291,8 @@ public class ShortcutService extends IShortcutService.Stub { final Context mContext; - private final Object mServiceLock = new Object(); + @VisibleForTesting + final Object mServiceLock = new Object(); private final Object mNonPersistentUsersLock = new Object(); private final Object mWtfLock = new Object(); @@ -982,7 +982,7 @@ public class ShortcutService extends IShortcutService.Stub { } @VisibleForTesting - void saveBaseState() { + void injectSaveBaseState() { try (ResilientAtomicFile file = getBaseStateFile()) { if (DEBUG || DEBUG_REBOOT) { Slog.d(TAG, "Saving to " + file.getBaseFile()); @@ -994,18 +994,7 @@ public class ShortcutService extends IShortcutService.Stub { outs = file.startWrite(); } - // Write to XML - TypedXmlSerializer out = Xml.resolveSerializer(outs); - out.startDocument(null, true); - out.startTag(null, TAG_ROOT); - - // Body. - // No locking required. Ok to add lock later if we save more data. - writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime.get()); - - // Epilogue. - out.endTag(null, TAG_ROOT); - out.endDocument(); + saveBaseStateAsXml(outs); // Close. injectFinishWrite(file, outs); @@ -1016,10 +1005,32 @@ public class ShortcutService extends IShortcutService.Stub { } } + @VisibleForTesting + protected void saveBaseStateAsXml(OutputStream outs) throws IOException { + // Write to XML + TypedXmlSerializer out = Xml.resolveSerializer(outs); + out.startDocument(null, true); + out.startTag(null, TAG_ROOT); + + // Body. + // No locking required. Ok to add lock later if we save more data. + writeTagValue(out, TAG_LAST_RESET_TIME, mRawLastResetTime.get()); + + // Epilogue. + out.endTag(null, TAG_ROOT); + out.endDocument(); + } + @GuardedBy("mServiceLock") private void loadBaseStateLocked() { mRawLastResetTime.set(0); + injectLoadBaseState(); + // Adjust the last reset time. + getLastResetTimeLocked(); + } + @VisibleForTesting + protected void injectLoadBaseState() { try (ResilientAtomicFile file = getBaseStateFile()) { if (DEBUG || DEBUG_REBOOT) { Slog.d(TAG, "Loading from " + file.getBaseFile()); @@ -1030,34 +1041,7 @@ public class ShortcutService extends IShortcutService.Stub { if (in == null) { throw new FileNotFoundException(file.getBaseFile().getAbsolutePath()); } - - TypedXmlPullParser parser = Xml.resolvePullParser(in); - - int type; - while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { - if (type != XmlPullParser.START_TAG) { - continue; - } - final int depth = parser.getDepth(); - // Check the root tag - final String tag = parser.getName(); - if (depth == 1) { - if (!TAG_ROOT.equals(tag)) { - Slog.v(TAG, "Invalid root tag: " + tag); - return; - } - continue; - } - // Assume depth == 2 - switch (tag) { - case TAG_LAST_RESET_TIME: - mRawLastResetTime.set(parseLongAttribute(parser, ATTR_VALUE)); - break; - default: - Slog.v(TAG, "Invalid tag: " + tag); - break; - } - } + loadBaseStateAsXml(in); } catch (FileNotFoundException e) { // Use the default } catch (IOException | XmlPullParserException e) { @@ -1067,8 +1051,38 @@ public class ShortcutService extends IShortcutService.Stub { return; } } - // Adjust the last reset time. - getLastResetTimeLocked(); + } + + @VisibleForTesting + protected void loadBaseStateAsXml(InputStream in) + throws IOException, XmlPullParserException { + TypedXmlPullParser parser = Xml.resolvePullParser(in); + + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { + if (type != XmlPullParser.START_TAG) { + continue; + } + final int depth = parser.getDepth(); + // Check the root tag + final String tag = parser.getName(); + if (depth == 1) { + if (!TAG_ROOT.equals(tag)) { + Slog.v(TAG, "Invalid root tag: " + tag); + return; + } + continue; + } + // Assume depth == 2 + switch (tag) { + case TAG_LAST_RESET_TIME: + mRawLastResetTime.set(parseLongAttribute(parser, ATTR_VALUE)); + break; + default: + Slog.v(TAG, "Invalid tag: " + tag); + break; + } + } } @VisibleForTesting @@ -1083,7 +1097,8 @@ public class ShortcutService extends IShortcutService.Stub { "user shortcut", null); } - private void saveUser(@UserIdInt int userId) { + @VisibleForTesting + protected void injectSaveUser(@UserIdInt int userId) { try (ResilientAtomicFile file = getUserFile(userId)) { FileOutputStream os = null; try { @@ -1092,8 +1107,14 @@ public class ShortcutService extends IShortcutService.Stub { } synchronized (mServiceLock) { + // Since we are not handling package deletion yet, or any single package + // changes, just clean the directory and rewrite all the ShortcutPackageItems. + final File root = injectUserDataPath(userId); + FileUtils.deleteContents(new File(root, DIRECTORY_PACKAGES)); + FileUtils.deleteContents(new File(root, DIRECTORY_LAUNCHERS)); os = file.startWrite(); saveUserInternalLocked(userId, os, /* forBackup= */ false); + getUserShortcutsLocked(userId).scheduleSaveAllLaunchersAndPackages(); } injectFinishWrite(file, os); @@ -1109,8 +1130,9 @@ public class ShortcutService extends IShortcutService.Stub { getUserShortcutsLocked(userId).logSharingShortcutStats(mMetricsLogger); } + @VisibleForTesting @GuardedBy("mServiceLock") - private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os, + protected void saveUserInternalLocked(@UserIdInt int userId, OutputStream os, boolean forBackup) throws IOException, XmlPullParserException { // Write to XML @@ -1138,8 +1160,9 @@ public class ShortcutService extends IShortcutService.Stub { Slog.w(TAG, String.format("Invalid tag '%s' found at depth %d", tag, depth)); } + @VisibleForTesting @Nullable - private ShortcutUser loadUserLocked(@UserIdInt int userId) { + protected ShortcutUser injectLoadUserLocked(@UserIdInt int userId) { try (ResilientAtomicFile file = getUserFile(userId)) { FileInputStream in = null; try { @@ -1157,12 +1180,13 @@ public class ShortcutService extends IShortcutService.Stub { } catch (Exception e) { // Remove corrupted file and retry. file.failRead(in, e); - return loadUserLocked(userId); + return injectLoadUserLocked(userId); } } } - private ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is, + @VisibleForTesting + protected ShortcutUser loadUserInternal(@UserIdInt int userId, InputStream is, boolean fromBackup) throws XmlPullParserException, IOException, InvalidFileFormatException { @@ -1240,9 +1264,9 @@ public class ShortcutService extends IShortcutService.Stub { for (int i = dirtyUserIds.size() - 1; i >= 0; i--) { final int userId = dirtyUserIds.get(i); if (userId == UserHandle.USER_NULL) { // USER_NULL for base state. - saveBaseState(); + injectSaveBaseState(); } else { - saveUser(userId); + injectSaveUser(userId); } } } catch (Exception e) { @@ -1349,7 +1373,7 @@ public class ShortcutService extends IShortcutService.Stub { ShortcutUser userPackages = mUsers.get(userId); if (userPackages == null) { - userPackages = loadUserLocked(userId); + userPackages = injectLoadUserLocked(userId); if (userPackages == null) { userPackages = new ShortcutUser(this, userId); } @@ -1430,8 +1454,9 @@ public class ShortcutService extends IShortcutService.Stub { * {@link ShortcutBitmapSaver#waitForAllSavesLocked()} to make sure there's no pending bitmap * saves are going on. */ + @VisibleForTesting @GuardedBy("mServiceLock") - private void cleanupDanglingBitmapDirectoriesLocked(@UserIdInt int userId) { + void cleanupDanglingBitmapDirectoriesLocked(@UserIdInt int userId) { if (DEBUG) { Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId); } @@ -2755,7 +2780,7 @@ public class ShortcutService extends IShortcutService.Stub { getPackageShortcutsLocked(packageName, userId) .resetRateLimitingForCommandLineNoSaving(); } - saveUser(userId); + injectSaveUser(userId); } // We override this method in unit tests to do a simpler check. @@ -4407,7 +4432,7 @@ public class ShortcutService extends IShortcutService.Stub { pw.println(); }); } - saveUser(userId); + injectSaveUser(userId); } // === Dump === diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java index bc8cc7ba29af..632fd16a32f7 100644 --- a/services/core/java/com/android/server/pm/ShortcutUser.java +++ b/services/core/java/com/android/server/pm/ShortcutUser.java @@ -21,16 +21,12 @@ import android.annotation.UserIdInt; import android.content.pm.ShortcutManager; import android.content.pm.UserPackage; import android.metrics.LogMaker; -import android.os.Binder; -import android.os.FileUtils; -import android.os.UserHandle; import android.text.TextUtils; import android.text.format.Formatter; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -49,8 +45,6 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.File; import java.io.IOException; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -63,7 +57,7 @@ class ShortcutUser { private static final String TAG = ShortcutService.TAG; static final String DIRECTORY_PACKAGES = "packages"; - static final String DIRECTORY_LUANCHERS = "launchers"; + static final String DIRECTORY_LAUNCHERS = "launchers"; static final String TAG_ROOT = "user"; private static final String TAG_LAUNCHER = "launcher"; @@ -322,41 +316,43 @@ class ShortcutUser { mService.injectBuildFingerprint()); } - if (!forBackup) { - // Since we are not handling package deletion yet, or any single package changes, just - // clean the directory and rewrite all the ShortcutPackageItems. - final File root = mService.injectUserDataPath(mUserId); - FileUtils.deleteContents(new File(root, DIRECTORY_PACKAGES)); - FileUtils.deleteContents(new File(root, DIRECTORY_LUANCHERS)); - } // Can't use forEachPackageItem due to the checked exceptions. + if (forBackup) { + int size = mLaunchers.size(); + for (int i = 0; i < size; i++) { + saveShortcutPackageItem(out, mLaunchers.valueAt(i)); + } + size = mPackages.size(); + for (int i = 0; i < size; i++) { + saveShortcutPackageItem(out, mPackages.valueAt(i)); + } + } + + out.endTag(null, TAG_ROOT); + } + + void scheduleSaveAllLaunchersAndPackages() { { final int size = mLaunchers.size(); for (int i = 0; i < size; i++) { - saveShortcutPackageItem(out, mLaunchers.valueAt(i), forBackup); + mLaunchers.valueAt(i).scheduleSave(); } } { final int size = mPackages.size(); for (int i = 0; i < size; i++) { - saveShortcutPackageItem(out, mPackages.valueAt(i), forBackup); + mPackages.valueAt(i).scheduleSave(); } } - - out.endTag(null, TAG_ROOT); } - private void saveShortcutPackageItem(TypedXmlSerializer out, ShortcutPackageItem spi, - boolean forBackup) throws IOException, XmlPullParserException { - if (forBackup) { - if (spi.getPackageUserId() != spi.getOwnerUserId()) { - return; // Don't save cross-user information. - } - spi.waitForBitmapSaves(); - spi.saveToXml(out, forBackup); - } else { - spi.scheduleSave(); + private void saveShortcutPackageItem(TypedXmlSerializer out, ShortcutPackageItem spi) + throws IOException, XmlPullParserException { + if (spi.getPackageUserId() != spi.getOwnerUserId()) { + return; // Don't save cross-user information. } + spi.waitForBitmapSaves(); + spi.saveToXml(out, true /* forBackup */); } public static ShortcutUser loadFromXml(ShortcutService s, TypedXmlPullParser parser, int userId, @@ -429,7 +425,7 @@ class ShortcutUser { } }); - forMainFilesIn(new File(root, DIRECTORY_LUANCHERS), (File f) -> { + forMainFilesIn(new File(root, DIRECTORY_LAUNCHERS), (File f) -> { final ShortcutLauncher sl = ShortcutLauncher.loadFromFile(f, ret, userId, fromBackup); if (sl != null) { diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java index dd60a155f2fb..8510ee70cc56 100644 --- a/services/core/java/com/android/server/pm/VerifyingSession.java +++ b/services/core/java/com/android/server/pm/VerifyingSession.java @@ -179,8 +179,7 @@ final class VerifyingSession { // Perform package verification and enable rollback (unless we are simply moving the // package). if (!mOriginInfo.mExisting) { - final boolean verifyForRollback = Flags.recoverabilityDetection() - ? !isARollback() : true; + final boolean verifyForRollback = !isARollback(); if (!isApex() && !isArchivedInstallation() && verifyForRollback) { // TODO(b/182426975): treat APEX as APK when APK verification is concerned sendApkVerificationRequest(pkgLite); diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 44d787f790cf..c31c287017c3 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -82,12 +82,10 @@ import android.util.LongSparseLongArray; import android.util.Slog; import android.util.SparseBooleanArray; -import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.infra.AndroidFuture; -import com.android.internal.policy.AttributeCache; import com.android.internal.util.IntPair; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.FgThread; @@ -167,6 +165,7 @@ public final class PermissionPolicyService extends SystemService { private Context mContext; private PackageManagerInternal mPackageManagerInternal; private PermissionManagerServiceInternal mPermissionManagerInternal; + private ActivityTaskManagerInternal mActivityTaskManagerInternal; private NotificationManagerInternal mNotificationManager; private TelephonyManager mTelephonyManager; private final KeyguardManager mKeyguardManager; @@ -189,6 +188,7 @@ public final class PermissionPolicyService extends SystemService { PackageManagerInternal.class); mPermissionManagerInternal = LocalServices.getService( PermissionManagerServiceInternal.class); + mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface( ServiceManager.getService(Context.APP_OPS_SERVICE)); @@ -1154,7 +1154,7 @@ public final class PermissionPolicyService extends SystemService { activityInfo.packageName, info.getCallingPackage(), info.getIntent(), info.getCheckedOptions(), activityInfo.name, true) - || isNoDisplayActivity(activityInfo)) { + || isNoDisplayActivity(activityInfo, info.getUserId())) { return; } UserHandle user = UserHandle.of(taskInfo.userId); @@ -1170,9 +1170,7 @@ public final class PermissionPolicyService extends SystemService { }; private void onActivityManagerReady() { - ActivityTaskManagerInternal atm = - LocalServices.getService(ActivityTaskManagerInternal.class); - atm.registerActivityStartInterceptor( + mActivityTaskManagerInternal.registerActivityStartInterceptor( ActivityInterceptorCallback.PERMISSION_POLICY_ORDERED_ID, mActivityInterceptorCallback); } @@ -1227,20 +1225,14 @@ public final class PermissionPolicyService extends SystemService { null, activityName, false); } - private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo) { + private boolean isNoDisplayActivity(@NonNull ActivityInfo aInfo, int userId) { final int themeResource = aInfo.getThemeResource(); if (themeResource == Resources.ID_NULL) { return false; } - boolean noDisplay = false; - final AttributeCache.Entry ent = AttributeCache.instance() - .get(aInfo.packageName, themeResource, R.styleable.Window, 0); - if (ent != null) { - noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); - } - - return noDisplay; + return mActivityTaskManagerInternal.isNoDisplay(aInfo.packageName, themeResource, + userId); } /** diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 76c5240ab623..980fb155999e 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1163,6 +1163,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private boolean shouldShowHub() { + final boolean hubEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), Settings.Secure.GLANCEABLE_HUB_ENABLED, + 1, mCurrentUserId) == 1; + + return mUserManagerInternal != null && mUserManagerInternal.isUserUnlocked(mCurrentUserId) + && hubEnabled && mDreamManagerInternal.dreamConditionActive(); + } + @VisibleForTesting void powerPress(long eventTime, int count, int displayId) { // SideFPS still needs to know about suppressed power buttons, in case it needs to block @@ -1251,7 +1260,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mContext.getContentResolver(), Settings.Secure.GLANCEABLE_HUB_ENABLED, 1, mCurrentUserId) == 1; - if (mDreamManagerInternal.isDreaming() || isKeyguardShowing()) { + if ((mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) + || isKeyguardShowing()) { // If the device is already dreaming or on keyguard, go to sleep. sleepDefaultDisplayFromPowerButton(eventTime, 0); break; @@ -1261,9 +1271,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { // show hub. boolean keyguardAvailable = !mLockPatternUtils.isLockScreenDisabled( mCurrentUserId); - if (mUserManagerInternal.isUserUnlocked(mCurrentUserId) && hubEnabled - && keyguardAvailable && mDreamManagerInternal.dreamConditionActive()) { - // If the hub can be launched, send a message to keyguard. + if (shouldShowHub() && keyguardAvailable) { + // If the hub can be launched, send a message to keyguard. We do not know if + // the hub is already running or not, keyguard handles turning screen off if + // it is. Bundle options = new Bundle(); options.putBoolean(EXTRA_TRIGGER_HUB, true); lockNow(options); @@ -1324,14 +1335,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { * @param isScreenOn Whether the screen is currently on. * @param noDreamAction The action to perform if dreaming is not possible. */ - private void attemptToDreamFromShortPowerButtonPress( + private boolean attemptToDreamFromShortPowerButtonPress( boolean isScreenOn, Runnable noDreamAction) { if (mShortPressOnPowerBehavior != SHORT_PRESS_POWER_DREAM_OR_SLEEP && mShortPressOnPowerBehavior != SHORT_PRESS_POWER_HUB_OR_DREAM_OR_SLEEP) { // If the power button behavior isn't one that should be able to trigger the dream, give // up. noDreamAction.run(); - return; + return false; } final DreamManagerInternal dreamManagerInternal = getDreamManagerInternal(); @@ -1339,7 +1350,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Slog.d(TAG, "Can't start dreaming when attempting to dream from short power" + " press (isScreenOn=" + isScreenOn + ")"); noDreamAction.run(); - return; + return false; } synchronized (mLock) { @@ -1350,6 +1361,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } dreamManagerInternal.requestDream(); + + return true; } /** @@ -2327,6 +2340,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowWakeUpPolicy getWindowWakeUpPolicy() { return new WindowWakeUpPolicy(mContext); } + + DreamManagerInternal getDreamManagerInternal() { + return LocalServices.getService(DreamManagerInternal.class); + } } /** {@inheritDoc} */ @@ -2345,7 +2362,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mInputManager = mContext.getSystemService(InputManager.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); - mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class); + mDreamManagerInternal = injector.getDreamManagerInternal(); mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); mAppOpsManager = mContext.getSystemService(AppOpsManager.class); mSensorPrivacyManager = mContext.getSystemService(SensorPrivacyManager.class); @@ -3701,15 +3718,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { break; case KeyEvent.KEYCODE_N: if (firstDown && event.isMetaPressed()) { - if (event.isCtrlPressed()) { - sendSystemKeyToStatusBarAsync(event); - notifyKeyGestureCompleted(event, - KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES); - } else { - toggleNotificationPanel(); - notifyKeyGestureCompleted(event, - KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL); - } + toggleNotificationPanel(); + notifyKeyGestureCompleted(event, + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL); return true; } break; @@ -6398,6 +6409,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { event.getDisplayId(), event.getKeyCode(), "wakeUpFromWakeKey")) { return; } + + if (!shouldShowHub() + && mShortPressOnPowerBehavior == SHORT_PRESS_POWER_HUB_OR_DREAM_OR_SLEEP + && event.getKeyCode() == KEYCODE_POWER + && attemptToDreamFromShortPowerButtonPress(false, () -> {})) { + // In the case that we should wake to dream and successfully initiate dreaming, do not + // continue waking up. Doing so will exit the dream state and cause UI to react + // accordingly. + return; + } + wakeUpFromWakeKey( event.getEventTime(), event.getKeyCode(), diff --git a/services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java index 6f6a7ff5064a..ca2237562fe1 100644 --- a/services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java +++ b/services/core/java/com/android/server/power/stats/format/ScreenPowerStatsLayout.java @@ -29,7 +29,8 @@ import com.android.internal.os.PowerStats; public class ScreenPowerStatsLayout extends PowerStatsLayout { private static final String EXTRA_DEVICE_SCREEN_COUNT = "dsc"; private static final String EXTRA_DEVICE_SCREEN_ON_DURATION_POSITION = "dsd"; - private static final String EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS = "dbd"; + private static final String EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS = "dbds"; + private static final String EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS_COMPAT = "dbd"; private static final String EXTRA_DEVICE_DOZE_DURATION_POSITION = "ddd"; private static final String EXTRA_DEVICE_DOZE_POWER_POSITION = "ddp"; private static final String EXTRA_UID_FOREGROUND_DURATION = "uf"; @@ -55,8 +56,14 @@ public class ScreenPowerStatsLayout extends PowerStatsLayout { PersistableBundle extras = descriptor.extras; mDisplayCount = extras.getInt(EXTRA_DEVICE_SCREEN_COUNT, 1); mDeviceScreenOnDurationPosition = extras.getInt(EXTRA_DEVICE_SCREEN_ON_DURATION_POSITION); - mDeviceBrightnessDurationPositions = extras.getIntArray( + mDeviceBrightnessDurationPositions = getIntArray(extras, EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS); + if (mDeviceBrightnessDurationPositions == null) { + // We should never put arrays in PowerStats.Descriptor because of the performance of + // .equals + mDeviceBrightnessDurationPositions = extras.getIntArray( + EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS_COMPAT); + } mDeviceScreenDozeDurationPosition = extras.getInt(EXTRA_DEVICE_DOZE_DURATION_POSITION); mDeviceScreenDozePowerPosition = extras.getInt(EXTRA_DEVICE_DOZE_POWER_POSITION); mUidTopActivityTimePosition = extras.getInt(EXTRA_UID_FOREGROUND_DURATION); @@ -67,7 +74,7 @@ public class ScreenPowerStatsLayout extends PowerStatsLayout { super.toExtras(extras); extras.putInt(EXTRA_DEVICE_SCREEN_COUNT, mDisplayCount); extras.putInt(EXTRA_DEVICE_SCREEN_ON_DURATION_POSITION, mDeviceScreenOnDurationPosition); - extras.putIntArray(EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS, + putIntArray(extras, EXTRA_DEVICE_BRIGHTNESS_DURATION_POSITIONS, mDeviceBrightnessDurationPositions); extras.putInt(EXTRA_DEVICE_DOZE_DURATION_POSITION, mDeviceScreenDozeDurationPosition); extras.putInt(EXTRA_DEVICE_DOZE_POWER_POSITION, mDeviceScreenDozePowerPosition); diff --git a/services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java b/services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java index e8df3ddfe5e8..c382534ac433 100644 --- a/services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java +++ b/services/core/java/com/android/server/power/stats/format/SensorPowerStatsLayout.java @@ -27,8 +27,10 @@ import java.util.Map; public class SensorPowerStatsLayout extends PowerStatsLayout { private static final String TAG = "SensorPowerStatsLayout"; - private static final String EXTRA_DEVICE_SENSOR_HANDLES = "dsh"; + private static final String EXTRA_DEVICE_SENSOR_HANDLES = "dshs"; + private static final String EXTRA_DEVICE_SENSOR_HANDLES_COMPAT = "dsh"; private static final String EXTRA_UID_SENSOR_POSITIONS = "usp"; + private static final String EXTRA_UID_SENSOR_POSITIONS_COMPAT = "usps"; private final SparseIntArray mSensorPositions = new SparseIntArray(); @@ -47,8 +49,14 @@ public class SensorPowerStatsLayout extends PowerStatsLayout { super(descriptor); PersistableBundle extras = descriptor.extras; - int[] handlers = extras.getIntArray(EXTRA_DEVICE_SENSOR_HANDLES); - int[] uidDurationPositions = extras.getIntArray(EXTRA_UID_SENSOR_POSITIONS); + int[] handlers = getIntArray(extras, EXTRA_DEVICE_SENSOR_HANDLES); + if (handlers == null) { + handlers = extras.getIntArray(EXTRA_DEVICE_SENSOR_HANDLES_COMPAT); + } + int[] uidDurationPositions = getIntArray(extras, EXTRA_UID_SENSOR_POSITIONS); + if (uidDurationPositions == null) { + uidDurationPositions = extras.getIntArray(EXTRA_UID_SENSOR_POSITIONS_COMPAT); + } if (handlers != null && uidDurationPositions != null) { for (int i = 0; i < handlers.length; i++) { @@ -69,8 +77,8 @@ public class SensorPowerStatsLayout extends PowerStatsLayout { uidDurationPositions[i] = mSensorPositions.valueAt(i); } - extras.putIntArray(EXTRA_DEVICE_SENSOR_HANDLES, handlers); - extras.putIntArray(EXTRA_UID_SENSOR_POSITIONS, uidDurationPositions); + putIntArray(extras, EXTRA_DEVICE_SENSOR_HANDLES, handlers); + putIntArray(extras, EXTRA_UID_SENSOR_POSITIONS, uidDurationPositions); } private void addUidSensorSection(int handle, String label) { diff --git a/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java index a783d543559f..53894a196d24 100644 --- a/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java +++ b/services/core/java/com/android/server/power/stats/processor/AggregatedPowerStats.java @@ -25,6 +25,7 @@ import android.os.PersistableBundle; import android.os.UserHandle; import android.text.format.DateFormat; import android.util.IndentingPrintWriter; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -347,7 +348,10 @@ class AggregatedPowerStats { Set<Integer> uids = new HashSet<>(); for (int i = 0; i < mPowerComponentStats.size(); i++) { - mPowerComponentStats.valueAt(i).collectUids(uids); + IntArray activeUids = mPowerComponentStats.valueAt(i).getActiveUids(); + for (int j = activeUids.size() - 1; j >= 0; j--) { + uids.add(activeUids.get(j)); + } } Integer[] allUids = uids.toArray(new Integer[uids.size()]); diff --git a/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java index d24ea83540cb..1d359335c6d8 100644 --- a/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/BasePowerStatsProcessor.java @@ -24,13 +24,12 @@ import static com.android.server.power.stats.processor.AggregatedPowerStatsConfi import android.os.BatteryConsumer; import android.os.PersistableBundle; +import android.util.IntArray; import com.android.internal.os.PowerStats; import com.android.server.power.stats.format.BasePowerStatsLayout; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.function.DoubleSupplier; class BasePowerStatsProcessor extends PowerStatsProcessor { @@ -125,11 +124,12 @@ class BasePowerStatsProcessor extends PowerStatsProcessor { mCumulativeDischargeUah = 0; mCumulativeDischargeDurationMs = 0; - List<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - - long durationMs = timestampMs - mStartTimestamp; - if (!uids.isEmpty()) { + // Note that we are calling `getUids` rather than `getActiveUids`, because this Processor + // deals with duration rather than power estimation, so it needs to process *all* known + // UIDs, not just the ones that contributed PowerStats + IntArray uids = stats.getUids(); + if (uids.size() != 0) { + long durationMs = timestampMs - mStartTimestamp; for (int i = uids.size() - 1; i >= 0; i--) { long[] uidStats = new long[sStatsLayout.getUidStatsArrayLength()]; sStatsLayout.setUidUsageDuration(uidStats, durationMs); diff --git a/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java index 9fe7f3e7a542..c89dddf45609 100644 --- a/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/BinaryStatePowerStatsProcessor.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.os.BatteryStats; import android.os.PersistableBundle; import android.os.Process; +import android.util.IntArray; import com.android.internal.os.PowerStats; import com.android.server.power.stats.UsageBasedPowerEstimator; @@ -27,7 +28,6 @@ import com.android.server.power.stats.format.BinaryStatePowerStatsLayout; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -190,13 +190,13 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor { } computeDevicePowerEstimates(stats, mPlan, mEnergyConsumerSupported); - combineDevicePowerEstimates(stats); - List<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - - computeUidActivityTotals(stats, uids); - computeUidPowerEstimates(stats, uids); + IntArray uids = stats.getActiveUids(); + if (uids.size() != 0) { + combineDevicePowerEstimates(stats); + computeUidActivityTotals(stats, uids); + computeUidPowerEstimates(stats, uids); + } } protected void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats, @@ -239,8 +239,7 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor { } } - private void computeUidActivityTotals(PowerComponentAggregatedPowerStats stats, - List<Integer> uids) { + private void computeUidActivityTotals(PowerComponentAggregatedPowerStats stats, IntArray uids) { for (int i = mPlan.uidStateEstimates.size() - 1; i >= 0; i--) { UidStateEstimate uidStateEstimate = mPlan.uidStateEstimates.get(i); Intermediates intermediates = @@ -259,8 +258,7 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor { } } - private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, - List<Integer> uids) { + private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, IntArray uids) { for (int i = mPlan.uidStateEstimates.size() - 1; i >= 0; i--) { UidStateEstimate uidStateEstimate = mPlan.uidStateEstimates.get(i); Intermediates intermediates = @@ -276,12 +274,13 @@ abstract class BinaryStatePowerStatsProcessor extends PowerStatsProcessor { int uid = uids.get(k); if (stats.getUidStats(mTmpUidStatsArray, uid, proportionalEstimate.stateValues)) { - double power = intermediates.power - * mStatsLayout.getUidUsageDuration(mTmpUidStatsArray) - / intermediates.duration; - mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); - stats.setUidStats(uid, proportionalEstimate.stateValues, - mTmpUidStatsArray); + long duration = mStatsLayout.getUidUsageDuration(mTmpUidStatsArray); + if (duration != 0) { + double power = intermediates.power * duration / intermediates.duration; + mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); + stats.setUidStats(uid, proportionalEstimate.stateValues, + mTmpUidStatsArray); + } } } } diff --git a/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java index 4c1a0db02273..c1cd3acf1656 100644 --- a/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/BluetoothPowerStatsProcessor.java @@ -16,12 +16,13 @@ package com.android.server.power.stats.processor; +import android.util.IntArray; + import com.android.internal.os.PowerProfile; import com.android.internal.os.PowerStats; import com.android.server.power.stats.UsageBasedPowerEstimator; import com.android.server.power.stats.format.BluetoothPowerStatsLayout; -import java.util.ArrayList; import java.util.List; class BluetoothPowerStatsProcessor extends PowerStatsProcessor { @@ -118,18 +119,19 @@ class BluetoothPowerStatsProcessor extends PowerStatsProcessor { combineDeviceStateEstimates(); - ArrayList<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - if (!uids.isEmpty()) { - for (int uid : uids) { - for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { - computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(i)); + IntArray uids = stats.getActiveUids(); + if (uids.size() != 0) { + for (int i = uids.size() - 1; i >= 0; i--) { + int uid = uids.get(i); + for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) { + computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(j)); } } - for (int uid : uids) { - for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { - computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(i)); + for (int i = uids.size() - 1; i >= 0; i--) { + int uid = uids.get(i); + for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) { + computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(j)); } } } @@ -297,8 +299,10 @@ class BluetoothPowerStatsProcessor extends PowerStatsProcessor { / intermediates.txBytes; } } - mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); - stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + if (power != 0) { + mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); + stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + } } } } diff --git a/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java index 17ceca6e3dc1..ab2489c81449 100644 --- a/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/CpuPowerStatsProcessor.java @@ -19,6 +19,7 @@ package com.android.server.power.stats.processor; import android.annotation.Nullable; import android.os.BatteryConsumer; import android.util.ArraySet; +import android.util.IntArray; import android.util.Log; import com.android.internal.os.CpuScalingPolicies; @@ -27,7 +28,6 @@ import com.android.internal.os.PowerStats; import com.android.server.power.stats.format.CpuPowerStatsLayout; import com.android.server.power.stats.format.WakelockPowerStatsLayout; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; @@ -119,6 +119,8 @@ class CpuPowerStatsProcessor extends PowerStatsProcessor { mTmpUidStatsArray = new long[descriptor.uidStatsArrayLength]; mWakelockDescriptor = null; + + initEnergyConsumerToPowerBracketMaps(); } /** @@ -157,9 +159,6 @@ class CpuPowerStatsProcessor extends PowerStatsProcessor { if (mPlan == null) { mPlan = new PowerEstimationPlan(stats.getConfig()); - if (mStatsLayout.getEnergyConsumerCount() != 0) { - initEnergyConsumerToPowerBracketMaps(); - } } Intermediates intermediates = new Intermediates(); @@ -189,12 +188,12 @@ class CpuPowerStatsProcessor extends PowerStatsProcessor { estimatePowerByDeviceState(stats, intermediates, wakelockStats); combineDeviceStateEstimates(); - ArrayList<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - if (!uids.isEmpty()) { - for (int uid : uids) { - for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { - estimateUidPowerConsumption(stats, uid, mPlan.uidStateEstimates.get(i), + IntArray uids = stats.getActiveUids(); + if (uids.size() != 0) { + for (int i = uids.size() - 1; i >= 0; i--) { + int uid = uids.get(i); + for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) { + estimateUidPowerConsumption(stats, uid, mPlan.uidStateEstimates.get(j), wakelockStats); } } @@ -255,6 +254,10 @@ class CpuPowerStatsProcessor extends PowerStatsProcessor { */ private void initEnergyConsumerToPowerBracketMaps() { int energyConsumerCount = mStatsLayout.getEnergyConsumerCount(); + if (energyConsumerCount == 0) { + return; + } + int powerBracketCount = mStatsLayout.getCpuPowerBracketCount(); mEnergyConsumerToCombinedEnergyConsumerMap = new int[energyConsumerCount]; @@ -545,8 +548,10 @@ class CpuPowerStatsProcessor extends PowerStatsProcessor { power = Math.max(0, power - wakelockPowerEstimate); } - mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); - stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + if (power != 0) { + mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); + stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + } } } } diff --git a/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java index 76adc47cc165..76ea7e841106 100644 --- a/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/CustomEnergyConsumerPowerStatsProcessor.java @@ -16,10 +16,11 @@ package com.android.server.power.stats.processor; +import android.util.IntArray; + import com.android.internal.os.PowerStats; import com.android.server.power.stats.format.EnergyConsumerPowerStatsLayout; -import java.util.ArrayList; import java.util.List; class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor { @@ -40,10 +41,8 @@ class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor { computeDevicePowerEstimates(stats); - List<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - - if (!uids.isEmpty()) { + IntArray uids = stats.getActiveUids(); + if (uids.size() != 0) { computeUidPowerEstimates(stats, uids); } } @@ -62,7 +61,7 @@ class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor { } private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, - List<Integer> uids) { + IntArray uids) { for (int i = mPlan.uidStateEstimates.size() - 1; i >= 0; i--) { UidStateEstimate uidStateEstimate = mPlan.uidStateEstimates.get(i); List<UidStateProportionalEstimate> proportionalEstimates = @@ -73,9 +72,12 @@ class CustomEnergyConsumerPowerStatsProcessor extends PowerStatsProcessor { int uid = uids.get(k); if (stats.getUidStats(mTmpUidStatsArray, uid, proportionalEstimate.stateValues)) { - sLayout.setUidPowerEstimate(mTmpUidStatsArray, - uCtoMah(sLayout.getUidConsumedEnergy(mTmpUidStatsArray, 0))); - stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + double power = uCtoMah(sLayout.getUidConsumedEnergy(mTmpUidStatsArray, 0)); + if (power != 0) { + sLayout.setUidPowerEstimate(mTmpUidStatsArray, power); + stats.setUidStats(uid, proportionalEstimate.stateValues, + mTmpUidStatsArray); + } } } } diff --git a/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java index b4c40de862b4..a544daad82f1 100644 --- a/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/MobileRadioPowerStatsProcessor.java @@ -19,6 +19,7 @@ import android.os.BatteryStats; import android.telephony.CellSignalStrength; import android.telephony.ModemActivityInfo; import android.telephony.ServiceState; +import android.util.IntArray; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -29,7 +30,6 @@ import com.android.internal.power.ModemPowerProfile; import com.android.server.power.stats.UsageBasedPowerEstimator; import com.android.server.power.stats.format.MobileRadioPowerStatsLayout; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -198,18 +198,19 @@ class MobileRadioPowerStatsProcessor extends PowerStatsProcessor { combineDeviceStateEstimates(); - ArrayList<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - if (!uids.isEmpty()) { - for (int uid : uids) { - for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { - computeUidRxTxTotals(stats, uid, mPlan.uidStateEstimates.get(i)); + IntArray uids = stats.getActiveUids(); + if (uids.size() != 0) { + for (int i = uids.size() - 1; i >= 0; i--) { + int uid = uids.get(i); + for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) { + computeUidRxTxTotals(stats, uid, mPlan.uidStateEstimates.get(j)); } } - for (int uid : uids) { - for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { - computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(i)); + for (int i = uids.size() - 1; i >= 0; i--) { + int uid = uids.get(i); + for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) { + computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(j)); } } } @@ -382,8 +383,10 @@ class MobileRadioPowerStatsProcessor extends PowerStatsProcessor { / intermediates.txPackets; } - mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); - stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + if (power != 0) { + mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); + stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + } if (DEBUG) { Slog.d(TAG, "UID: " + uid diff --git a/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java b/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java index 28474a554b38..69325757c79d 100644 --- a/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java +++ b/services/core/java/com/android/server/power/stats/processor/MultiStateStats.java @@ -16,6 +16,7 @@ package com.android.server.power.stats.processor; +import android.annotation.Nullable; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -333,9 +334,9 @@ class MultiStateStats { /** * Adds the delta to the metrics. The number of values must correspond to the dimension count - * supplied to the Factory constructor + * supplied to the Factory constructor. Null values is equivalent to an array of zeros. */ - void increment(long[] values, long timestampMs) { + void increment(@Nullable long[] values, long timestampMs) { mCounter.incrementValues(values, timestampMs); mTracking = true; } diff --git a/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java b/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java index d4f8fd92fc6c..f9b9da9171cb 100644 --- a/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java +++ b/services/core/java/com/android/server/power/stats/processor/PowerComponentAggregatedPowerStats.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.os.BatteryStats; import android.os.UserHandle; import android.util.IndentingPrintWriter; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -34,7 +35,6 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.StringWriter; import java.util.Arrays; -import java.util.Collection; import java.util.function.IntConsumer; /** @@ -72,11 +72,11 @@ class PowerComponentAggregatedPowerStats { private MultiStateStats mDeviceStats; private final SparseArray<MultiStateStats> mStateStats = new SparseArray<>(); private final SparseArray<UidStats> mUidStats = new SparseArray<>(); - private long[] mZeroArray; private static class UidStats { public int[] states; public MultiStateStats stats; + public boolean hasPowerStats; public boolean updated; } @@ -200,6 +200,7 @@ class PowerComponentAggregatedPowerStats { if (uidStats.stats == null) { createUidStats(uidStats, mPowerStatsTimestamp); } + uidStats.hasPowerStats = true; uidStats.stats.setStats(states, values); } @@ -240,6 +241,7 @@ class PowerComponentAggregatedPowerStats { } uidStats.stats.increment(powerStats.uidStats.valueAt(i), timestampMs); uidStats.updated = true; + uidStats.hasPowerStats = true; } // For UIDs not mentioned in the PowerStats object, we must assume a 0 increment. @@ -248,11 +250,8 @@ class PowerComponentAggregatedPowerStats { for (int i = mUidStats.size() - 1; i >= 0; i--) { PowerComponentAggregatedPowerStats.UidStats uidStats = mUidStats.valueAt(i); if (!uidStats.updated && uidStats.stats != null) { - if (mZeroArray == null - || mZeroArray.length != mPowerStatsDescriptor.uidStatsArrayLength) { - mZeroArray = new long[mPowerStatsDescriptor.uidStatsArrayLength]; - } - uidStats.stats.increment(mZeroArray, timestampMs); + // Null stands for an array of zeros + uidStats.stats.increment(null, timestampMs); } uidStats.updated = false; } @@ -267,6 +266,7 @@ class PowerComponentAggregatedPowerStats { mStateStats.clear(); for (int i = mUidStats.size() - 1; i >= 0; i--) { mUidStats.valueAt(i).stats = null; + mUidStats.valueAt(i).hasPowerStats = false; } } @@ -290,12 +290,26 @@ class PowerComponentAggregatedPowerStats { return uidStats; } - void collectUids(Collection<Integer> uids) { + IntArray getUids() { + IntArray uids = new IntArray(mUidStats.size()); + for (int i = mUidStats.size() - 1; i >= 0; i--) { + UidStats uidStats = mUidStats.valueAt(i); + if (uidStats.stats != null) { + uids.add(mUidStats.keyAt(i)); + } + } + return uids; + } + + IntArray getActiveUids() { + IntArray uids = new IntArray(mUidStats.size()); for (int i = mUidStats.size() - 1; i >= 0; i--) { - if (mUidStats.valueAt(i).stats != null) { + UidStats uidStats = mUidStats.valueAt(i); + if (uidStats.hasPowerStats) { uids.add(mUidStats.keyAt(i)); } } + return uids; } boolean getDeviceStats(long[] outValues, int[] deviceStates) { @@ -516,6 +530,7 @@ class PowerComponentAggregatedPowerStats { if (uidStats.stats == null) { createUidStats(uidStats, UNKNOWN); } + uidStats.hasPowerStats = true; if (!uidStats.stats.readFromXml(parser)) { return false; } diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java index 177d12988a27..634415ece806 100644 --- a/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java +++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsExporter.java @@ -21,6 +21,7 @@ import android.os.AggregateBatteryConsumer; import android.os.BatteryConsumer; import android.os.BatteryUsageStats; import android.os.UidBatteryConsumer; +import android.util.IntArray; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -31,7 +32,6 @@ import com.android.server.power.stats.PowerStatsStore; import com.android.server.power.stats.format.BasePowerStatsLayout; import com.android.server.power.stats.format.PowerStatsLayout; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeUnit; @@ -180,8 +180,7 @@ class PowerStatsExporter { } } if (layout.isUidPowerAttributionSupported()) { - populateBatteryConsumers(batteryUsageStatsBuilder, - powerComponentStats, layout); + populateBatteryConsumers(batteryUsageStatsBuilder, powerComponentStats, layout); } populateBatteryLevelInfo(batteryUsageStatsBuilder, batteryLevelInfo); @@ -258,6 +257,11 @@ class PowerStatsExporter { BatteryUsageStats.Builder batteryUsageStatsBuilder, PowerComponentAggregatedPowerStats powerComponentStats, PowerStatsLayout layout) { + IntArray uids = powerComponentStats.getUids(); + if (uids.size() == 0) { + return; + } + AggregatedPowerStatsConfig.PowerComponent powerComponent = powerComponentStats.getConfig(); PowerStats.Descriptor descriptor = powerComponentStats.getPowerStatsDescriptor(); long[] uidStats = new long[descriptor.uidStatsArrayLength]; @@ -273,8 +277,6 @@ class PowerStatsExporter { breakDownByProcState = false; } - ArrayList<Integer> uids = new ArrayList<>(); - powerComponentStats.collectUids(uids); for (int screenState = 0; screenState < BatteryConsumer.SCREEN_STATE_COUNT; screenState++) { if (batteryUsageStatsBuilder.isScreenStateDataNeeded()) { if (screenState == BatteryConsumer.SCREEN_STATE_UNSPECIFIED) { @@ -303,7 +305,7 @@ class PowerStatsExporter { private void populateUidBatteryConsumers( BatteryUsageStats.Builder batteryUsageStatsBuilder, PowerComponentAggregatedPowerStats powerComponentStats, PowerStatsLayout layout, - List<Integer> uids, AggregatedPowerStatsConfig.PowerComponent powerComponent, + IntArray uids, AggregatedPowerStatsConfig.PowerComponent powerComponent, long[] uidStats, boolean breakDownByProcState, @BatteryConsumer.ScreenState int screenState, @BatteryConsumer.PowerState int powerState) { @@ -319,7 +321,8 @@ class PowerStatsExporter { long[] durationByProcState = new long[breakDownByProcState ? BatteryConsumer.PROCESS_STATE_COUNT : 1]; double powerAllApps = 0; - for (int uid : uids) { + for (int i = uids.size() - 1; i >= 0; i--) { + int uid = uids.get(i); UidBatteryConsumer.Builder builder = batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid); diff --git a/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java index 8e7498f38fcb..9df3d7eea27b 100644 --- a/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/ScreenPowerStatsProcessor.java @@ -27,6 +27,7 @@ import static com.android.server.power.stats.processor.AggregatedPowerStatsConfi import static com.android.server.power.stats.processor.AggregatedPowerStatsConfig.STATE_SCREEN; import android.os.BatteryStats; +import android.util.IntArray; import android.util.Slog; import com.android.internal.os.PowerProfile; @@ -34,7 +35,6 @@ import com.android.internal.os.PowerStats; import com.android.server.power.stats.UsageBasedPowerEstimator; import com.android.server.power.stats.format.ScreenPowerStatsLayout; -import java.util.ArrayList; import java.util.List; class ScreenPowerStatsProcessor extends PowerStatsProcessor { @@ -116,10 +116,8 @@ class ScreenPowerStatsProcessor extends PowerStatsProcessor { computeDevicePowerEstimates(stats); combineDeviceStateEstimates(); - List<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - - if (!uids.isEmpty()) { + IntArray uids = stats.getActiveUids(); + if (uids.size() != 0) { computeUidPowerEstimates(stats, uids); } mPlan.resetIntermediates(); @@ -197,7 +195,7 @@ class ScreenPowerStatsProcessor extends PowerStatsProcessor { } private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, - List<Integer> uids) { + IntArray uids) { int[] uidStateValues = new int[stats.getConfig().getUidStateConfig().length]; uidStateValues[STATE_SCREEN] = SCREEN_STATE_ON; uidStateValues[STATE_PROCESS_STATE] = PROCESS_STATE_UNSPECIFIED; @@ -232,9 +230,11 @@ class ScreenPowerStatsProcessor extends PowerStatsProcessor { int uid = uids.get(j); if (stats.getUidStats(mTmpUidStatsArray, uid, uidStateValues)) { long duration = mStatsLayout.getUidTopActivityDuration(mTmpUidStatsArray); - double power = intermediates.power * duration / totalTopActivityDuration; - mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); - stats.setUidStats(uid, uidStateValues, mTmpUidStatsArray); + if (duration != 0) { + double power = intermediates.power * duration / totalTopActivityDuration; + mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); + stats.setUidStats(uid, uidStateValues, mTmpUidStatsArray); + } } } } diff --git a/services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java index 0bb028bce5af..ba728d36d561 100644 --- a/services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/SensorPowerStatsProcessor.java @@ -21,6 +21,7 @@ import android.hardware.SensorManager; import android.os.BatteryConsumer; import android.os.BatteryStats; import android.os.PersistableBundle; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -28,7 +29,6 @@ import com.android.internal.os.PowerStats; import com.android.server.power.stats.format.PowerStatsLayout; import com.android.server.power.stats.format.SensorPowerStatsLayout; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Supplier; @@ -207,11 +207,11 @@ class SensorPowerStatsProcessor extends PowerStatsProcessor { mPlan = new PowerEstimationPlan(stats.getConfig()); } - List<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - - computeUidPowerEstimates(stats, uids); - computeDevicePowerEstimates(stats); + IntArray uids = stats.getActiveUids(); + if (uids.size() != 0) { + computeUidPowerEstimates(stats, uids); + computeDevicePowerEstimates(stats); + } mPlan.resetIntermediates(); } @@ -239,9 +239,7 @@ class SensorPowerStatsProcessor extends PowerStatsProcessor { mLastUpdateTimestamp = timestamp; } - private void computeUidPowerEstimates( - PowerComponentAggregatedPowerStats stats, - List<Integer> uids) { + private void computeUidPowerEstimates(PowerComponentAggregatedPowerStats stats, IntArray uids) { List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); int[] uidSensorDurationPositions = new int[sensorList.size()]; double[] sensorPower = new double[sensorList.size()]; @@ -292,8 +290,7 @@ class SensorPowerStatsProcessor extends PowerStatsProcessor { } } - private void computeDevicePowerEstimates( - PowerComponentAggregatedPowerStats stats) { + private void computeDevicePowerEstimates(PowerComponentAggregatedPowerStats stats) { for (int i = mPlan.combinedDeviceStateEstimations.size() - 1; i >= 0; i--) { CombinedDeviceStateEstimate estimation = mPlan.combinedDeviceStateEstimations.get(i); diff --git a/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java b/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java index 0df01cf7e5d1..8cc0b6eb6150 100644 --- a/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java +++ b/services/core/java/com/android/server/power/stats/processor/WifiPowerStatsProcessor.java @@ -16,6 +16,7 @@ package com.android.server.power.stats.processor; +import android.util.IntArray; import android.util.Slog; import com.android.internal.os.PowerProfile; @@ -23,7 +24,6 @@ import com.android.internal.os.PowerStats; import com.android.server.power.stats.UsageBasedPowerEstimator; import com.android.server.power.stats.format.WifiPowerStatsLayout; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -148,18 +148,19 @@ class WifiPowerStatsProcessor extends PowerStatsProcessor { combineDeviceStateEstimates(); - ArrayList<Integer> uids = new ArrayList<>(); - stats.collectUids(uids); - if (!uids.isEmpty()) { - for (int uid : uids) { - for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { - computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(i)); + IntArray uids = stats.getActiveUids(); + if (uids.size() != 0) { + for (int i = uids.size() - 1; i >= 0; i--) { + int uid = uids.get(i); + for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) { + computeUidActivityTotals(stats, uid, mPlan.uidStateEstimates.get(j)); } } - for (int uid : uids) { - for (int i = 0; i < mPlan.uidStateEstimates.size(); i++) { - computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(i)); + for (int i = uids.size() - 1; i >= 0; i--) { + int uid = uids.get(i); + for (int j = 0; j < mPlan.uidStateEstimates.size(); j++) { + computeUidPowerEstimates(stats, uid, mPlan.uidStateEstimates.get(j)); } } } @@ -374,8 +375,10 @@ class WifiPowerStatsProcessor extends PowerStatsProcessor { / intermediates.batchedScanDuration; } } - mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); - stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + if (power != 0) { + mStatsLayout.setUidPowerEstimate(mTmpUidStatsArray, power); + stats.setUidStats(uid, proportionalEstimate.stateValues, mTmpUidStatsArray); + } if (DEBUG) { Slog.d(TAG, "UID: " + uid diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java index ab756f2a755b..5347ca46ab31 100644 --- a/services/core/java/com/android/server/rollback/Rollback.java +++ b/services/core/java/com/android/server/rollback/Rollback.java @@ -29,7 +29,6 @@ import android.annotation.WorkerThread; import android.content.Context; import android.content.Intent; import android.content.IntentSender; -import android.content.pm.Flags; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; @@ -965,9 +964,7 @@ class Rollback { ipw.println("-stateDescription: " + mStateDescription); ipw.println("-timestamp: " + getTimestamp()); ipw.println("-rollbackLifetimeMillis: " + getRollbackLifetimeMillis()); - if (Flags.recoverabilityDetection()) { - ipw.println("-rollbackImpactLevel: " + info.getRollbackImpactLevel()); - } + ipw.println("-rollbackImpactLevel: " + info.getRollbackImpactLevel()); ipw.println("-isStaged: " + isStaged()); ipw.println("-originalSessionId: " + getOriginalSessionId()); ipw.println("-packages:"); diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 2e6be5bb56a8..9ed52d8b3504 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -1244,17 +1244,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba rollback.makeAvailable(); mPackageHealthObserver.notifyRollbackAvailable(rollback.info); - if (Flags.recoverabilityDetection()) { - if (rollback.info.getRollbackImpactLevel() == PackageManager.ROLLBACK_USER_IMPACT_LOW) { - // TODO(zezeozue): Provide API to explicitly start observing instead - // of doing this for all rollbacks. If we do this for all rollbacks, - // should document in PackageInstaller.SessionParams#setEnableRollback - // After enabling and committing any rollback, observe packages and - // prepare to rollback if packages crashes too frequently. - mPackageWatchdog.startExplicitHealthCheck(rollback.getPackageNames(), - mRollbackLifetimeDurationInMillis, mPackageHealthObserver); - } - } else { + if (rollback.info.getRollbackImpactLevel() == PackageManager.ROLLBACK_USER_IMPACT_LOW) { + // TODO(zezeozue): Provide API to explicitly start observing instead + // of doing this for all rollbacks. If we do this for all rollbacks, + // should document in PackageInstaller.SessionParams#setEnableRollback + // After enabling and committing any rollback, observe packages and + // prepare to rollback if packages crashes too frequently. mPackageWatchdog.startExplicitHealthCheck(rollback.getPackageNames(), mRollbackLifetimeDurationInMillis, mPackageHealthObserver); } diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index 50db1e4ac30e..6dc40323f2ee 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -197,9 +197,7 @@ class RollbackStore { json.put("isStaged", rollback.isStaged()); json.put("causePackages", versionedPackagesToJson(rollback.getCausePackages())); json.put("committedSessionId", rollback.getCommittedSessionId()); - if (Flags.recoverabilityDetection()) { - json.put("rollbackImpactLevel", rollback.getRollbackImpactLevel()); - } + json.put("rollbackImpactLevel", rollback.getRollbackImpactLevel()); return json; } @@ -211,11 +209,9 @@ class RollbackStore { versionedPackagesFromJson(json.getJSONArray("causePackages")), json.getInt("committedSessionId")); - if (Flags.recoverabilityDetection()) { - // to make it backward compatible. - rollbackInfo.setRollbackImpactLevel(json.optInt("rollbackImpactLevel", - PackageManager.ROLLBACK_USER_IMPACT_LOW)); - } + // to make it backward compatible. + rollbackInfo.setRollbackImpactLevel(json.optInt("rollbackImpactLevel", + PackageManager.ROLLBACK_USER_IMPACT_LOW)); return rollbackInfo; } diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java index 342b864c6473..281aeb68f224 100644 --- a/services/core/java/com/android/server/storage/StorageSessionController.java +++ b/services/core/java/com/android/server/storage/StorageSessionController.java @@ -156,14 +156,15 @@ public final class StorageSessionController { StorageUserConnection connection = null; synchronized (mLock) { connection = mConnections.get(connectionUserId); - if (connection != null) { - Slog.i(TAG, "Notifying volume state changed for session with id: " + sessionId); - connection.notifyVolumeStateChanged(sessionId, - vol.buildStorageVolume(mContext, vol.getMountUserId(), false)); - } else { - Slog.w(TAG, "No available storage user connection for userId : " - + connectionUserId); - } + } + + if (connection != null) { + Slog.i(TAG, "Notifying volume state changed for session with id: " + sessionId); + connection.notifyVolumeStateChanged(sessionId, + vol.buildStorageVolume(mContext, vol.getMountUserId(), false)); + } else { + Slog.w(TAG, "No available storage user connection for userId : " + + connectionUserId); } } @@ -225,16 +226,18 @@ public final class StorageSessionController { String sessionId = vol.getId(); int userId = getConnectionUserIdForVolume(vol); + StorageUserConnection connection = null; synchronized (mLock) { - StorageUserConnection connection = mConnections.get(userId); - if (connection != null) { - Slog.i(TAG, "Removed session for vol with id: " + sessionId); - connection.removeSession(sessionId); - return connection; - } else { - Slog.w(TAG, "Session already removed for vol with id: " + sessionId); - return null; - } + connection = mConnections.get(userId); + } + + if (connection != null) { + Slog.i(TAG, "Removed session for vol with id: " + sessionId); + connection.removeSession(sessionId); + return connection; + } else { + Slog.w(TAG, "Session already removed for vol with id: " + sessionId); + return null; } } diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java index 1b6ce9dacfa9..64b52b175252 100644 --- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java +++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java @@ -176,14 +176,14 @@ final class VendorVibrationSession extends IVibrationSession.Stub @Override public void onCancel() { - Slog.d(TAG, "Cancellation signal received, cancelling vibration session..."); + Slog.d(TAG, "Session cancellation signal received, aborting vibration session..."); requestEndSession(Status.CANCELLED_BY_USER, /* shouldAbort= */ true, /* isVendorRequest= */ true); } @Override public void binderDied() { - Slog.d(TAG, "Binder died, cancelling vibration session..."); + Slog.d(TAG, "Session binder died, aborting vibration session..."); requestEndSession(Status.CANCELLED_BINDER_DIED, /* shouldAbort= */ true, /* isVendorRequest= */ false); } @@ -219,18 +219,20 @@ final class VendorVibrationSession extends IVibrationSession.Stub @Override public void notifyVibratorCallback(int vibratorId, long vibrationId) { - // Ignore it, the session vibration playback doesn't depend on HAL timings + Slog.d(TAG, "Vibration callback received for vibration " + vibrationId + + " on vibrator " + vibratorId + ", ignoring..."); } @Override public void notifySyncedVibratorsCallback(long vibrationId) { - // Ignore it, the session vibration playback doesn't depend on HAL timings + Slog.d(TAG, "Synced vibration callback received for vibration " + vibrationId + + ", ignoring..."); } @Override public void notifySessionCallback() { + Slog.d(TAG, "Session callback received, ending vibration session..."); synchronized (mLock) { - Slog.d(TAG, "Session callback received, ending vibration session..."); // If end was not requested then the HAL has cancelled the session. maybeSetEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON, /* isVendorRequest= */ false); @@ -307,7 +309,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub } } if (isAlreadyEnded) { - // Session already ended, make sure we end it in the HAL. + Slog.d(TAG, "Session already ended after starting the HAL, aborting..."); mHandler.post(() -> mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true)); } } @@ -335,8 +337,8 @@ final class VendorVibrationSession extends IVibrationSession.Stub public boolean maybeSetVibrationConductor(VibrationStepConductor conductor) { synchronized (mLock) { if (mConductor != null) { - Slog.d(TAG, "Vibration session still dispatching previous vibration," - + " new vibration ignored"); + Slog.d(TAG, "Session still dispatching previous vibration, new vibration " + + conductor.getVibration().id + " ignored"); return false; } mConductor = conductor; @@ -345,19 +347,22 @@ final class VendorVibrationSession extends IVibrationSession.Stub } private void requestEndSession(Status status, boolean shouldAbort, boolean isVendorRequest) { + Slog.d(TAG, "Session end request received with status " + status); boolean shouldTriggerSessionHook = false; synchronized (mLock) { maybeSetEndRequestLocked(status, isVendorRequest); - if (isStarted()) { - // Always trigger session hook after it has started, in case new request aborts an - // already finishing session. Wait for HAL callback before actually ending here. + if (!isEnded() && isStarted()) { + // Trigger session hook even if it was already triggered, in case a second request + // is aborting the ongoing/ending session. This might cause it to end right away. + // Wait for HAL callback before setting the end status. shouldTriggerSessionHook = true; } else { - // Session did not start in the HAL, end it right away. + // Session not active in the HAL, set end status right away. maybeSetStatusToRequestedLocked(); } } if (shouldTriggerSessionHook) { + Slog.d(TAG, "Requesting HAL session end with abort=" + shouldAbort); mHandler.post(() -> mManagerHooks.endSession(mSessionId, shouldAbort)); } } @@ -368,6 +373,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub // End already requested, keep first requested status and time. return; } + Slog.d(TAG, "Session end request accepted for status " + status); mEndStatusRequest = status; mEndedByVendor = isVendorRequest; mEndTime = System.currentTimeMillis(); @@ -400,6 +406,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub // No end status was requested, nothing to set. return; } + Slog.d(TAG, "Session end request applied for status " + mEndStatusRequest); mStatus = mEndStatusRequest; // Run client callback in separate thread. final Status endStatus = mStatus; @@ -407,7 +414,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub try { mCallback.onFinished(toSessionStatus(endStatus)); } catch (RemoteException e) { - Slog.e(TAG, "Error notifying vendor session is finishing", e); + Slog.e(TAG, "Error notifying vendor session finished", e); } }); } diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index 804cf4663bfd..75b1b202bcfd 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -61,6 +61,7 @@ import android.os.VibratorInfo; import android.os.vibrator.Flags; import android.os.vibrator.IVibrationSessionCallback; import android.os.vibrator.PrebakedSegment; +import android.os.vibrator.PrimitiveSegment; import android.os.vibrator.VibrationConfig; import android.os.vibrator.VibrationEffectSegment; import android.os.vibrator.VibratorInfoFactory; @@ -786,7 +787,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { synchronized (mLock) { if (DEBUG) { - Slog.d(TAG, "Starting session " + session.getSessionId()); + Slog.d(TAG, "Starting vendor session " + session.getSessionId()); } Status ignoreStatus = null; @@ -864,13 +865,16 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { // Session already ended, possibly cancelled by app cancellation signal. return session.getStatus(); } - int mode = startAppOpModeLocked(session.getCallerInfo()); + CallerInfo callerInfo = session.getCallerInfo(); + int mode = startAppOpModeLocked(callerInfo); switch (mode) { case AppOpsManager.MODE_ALLOWED: Trace.asyncTraceBegin(TRACE_TAG_VIBRATOR, "vibration", 0); // Make sure mCurrentVibration is set while triggering the HAL. mCurrentSession = session; if (!session.linkToDeath()) { + // Shouldn't happen. The method call already logs. + finishAppOpModeLocked(callerInfo); mCurrentSession = null; return Status.IGNORED_ERROR_TOKEN; } @@ -878,14 +882,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { Slog.e(TAG, "Error starting session " + sessionId + " on vibrators " + Arrays.toString(session.getVibratorIds())); session.unlinkToDeath(); + finishAppOpModeLocked(callerInfo); mCurrentSession = null; return Status.IGNORED_UNSUPPORTED; } session.notifyStart(); return null; case AppOpsManager.MODE_ERRORED: - Slog.w(TAG, "Start AppOpsManager operation errored for uid " - + session.getCallerInfo().uid); + Slog.w(TAG, "Start AppOpsManager operation errored for uid " + callerInfo.uid); return Status.IGNORED_ERROR_APP_OPS; default: return Status.IGNORED_APP_OPS; @@ -1081,11 +1085,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @Nullable private Status startVibrationOnThreadLocked(SingleVibrationSession session) { if (DEBUG) { - Slog.d(TAG, "Starting vibration " + session.getVibration().id + " on thread"); + Slog.d(TAG, "Starting vibration " + session.getVibration().id + " on thread"); } VibrationStepConductor conductor = createVibrationStepConductor(session.getVibration()); session.setVibrationConductor(conductor); - int mode = startAppOpModeLocked(session.getCallerInfo()); + CallerInfo callerInfo = session.getCallerInfo(); + int mode = startAppOpModeLocked(callerInfo); switch (mode) { case AppOpsManager.MODE_ALLOWED: Trace.asyncTraceBegin(TRACE_TAG_VIBRATOR, "vibration", 0); @@ -1093,19 +1098,21 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mCurrentSession = session; if (!mCurrentSession.linkToDeath()) { // Shouldn't happen. The method call already logs. + finishAppOpModeLocked(callerInfo); mCurrentSession = null; // Aborted. return Status.IGNORED_ERROR_TOKEN; } if (!mVibrationThread.runVibrationOnVibrationThread(conductor)) { // Shouldn't happen. The method call already logs. session.setVibrationConductor(null); // Rejected by thread, clear it in session. + mCurrentSession.unlinkToDeath(); + finishAppOpModeLocked(callerInfo); mCurrentSession = null; // Aborted. return Status.IGNORED_ERROR_SCHEDULING; } return null; case AppOpsManager.MODE_ERRORED: - Slog.w(TAG, "Start AppOpsManager operation errored for uid " - + session.getCallerInfo().uid); + Slog.w(TAG, "Start AppOpsManager operation errored for uid " + callerInfo.uid); return Status.IGNORED_ERROR_APP_OPS; default: return Status.IGNORED_APP_OPS; @@ -1494,6 +1501,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private int checkAppOpModeLocked(CallerInfo callerInfo) { int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.attrs.getAudioUsage(), callerInfo.uid, callerInfo.opPkg); + if (DEBUG) { + int opMode = mAppOps.checkOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.uid, + callerInfo.opPkg); + Slog.d(TAG, "Check AppOp mode VIBRATE for uid " + callerInfo.uid + " and package " + + callerInfo.opPkg + " returned audio=" + AppOpsManager.MODE_NAMES[mode] + + ", op=" + AppOpsManager.MODE_NAMES[opMode]); + } int fixedMode = fixupAppOpModeLocked(mode, callerInfo.attrs); if (mode != fixedMode && fixedMode == AppOpsManager.MODE_ALLOWED) { // If we're just ignoring the vibration op then this is set by DND and we should ignore @@ -1507,9 +1521,13 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { /** Start an operation in {@link AppOpsManager}, if allowed. */ @GuardedBy("mLock") private int startAppOpModeLocked(CallerInfo callerInfo) { - return fixupAppOpModeLocked( - mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.uid, callerInfo.opPkg), - callerInfo.attrs); + int mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, callerInfo.uid, + callerInfo.opPkg); + if (DEBUG) { + Slog.d(TAG, "Start AppOp mode VIBRATE for uid " + callerInfo.uid + " and package " + + callerInfo.opPkg + " returned " + AppOpsManager.MODE_NAMES[mode]); + } + return fixupAppOpModeLocked(mode, callerInfo.attrs); } /** @@ -1518,6 +1536,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { */ @GuardedBy("mLock") private void finishAppOpModeLocked(CallerInfo callerInfo) { + if (DEBUG) { + Slog.d(TAG, "Finish AppOp mode VIBRATE for uid " + callerInfo.uid + " and package " + + callerInfo.opPkg); + } mAppOps.finishOp(AppOpsManager.OP_VIBRATE, callerInfo.uid, callerInfo.opPkg); } @@ -2651,7 +2673,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { CombinedVibration.ParallelCombination combination = CombinedVibration.startParallel(); while ("-v".equals(getNextOption())) { - int vibratorId = Integer.parseInt(getNextArgRequired()); + int vibratorId = parseInt(getNextArgRequired(), "Expected vibrator id after -v"); combination.addVibrator(vibratorId, nextEffect()); } runVibrate(commonOptions, combination.combine()); @@ -2663,7 +2685,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { CombinedVibration.SequentialCombination combination = CombinedVibration.startSequential(); while ("-v".equals(getNextOption())) { - int vibratorId = Integer.parseInt(getNextArgRequired()); + int vibratorId = parseInt(getNextArgRequired(), "Expected vibrator id after -v"); combination.addNext(vibratorId, nextEffect()); } runVibrate(commonOptions, combination.combine()); @@ -2688,7 +2710,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private int runHapticFeedback() { CommonOptions commonOptions = new CommonOptions(); - int constant = Integer.parseInt(getNextArgRequired()); + int constant = parseInt(getNextArgRequired(), "Expected haptic feedback constant id"); IBinder deathBinder = commonOptions.background ? VibratorManagerService.this : mShellCallbacksToken; @@ -2715,6 +2737,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { addPrebakedToComposition(composition); } else if ("primitives".equals(nextArg)) { addPrimitivesToComposition(composition); + } else if ("envelope".equals(nextArg)) { + addEnvelopeToComposition(composition); } else { // nextArg is not an effect, finish reading. break; @@ -2734,17 +2758,135 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { if ("-a".equals(nextOption)) { hasAmplitude = true; } else if ("-w".equals(nextOption)) { - delay = Integer.parseInt(getNextArgRequired()); + delay = parseInt(getNextArgRequired(), "Expected delay millis after -w"); } } - long duration = Long.parseLong(getNextArgRequired()); - int amplitude = hasAmplitude ? Integer.parseInt(getNextArgRequired()) + long duration = parseInt(getNextArgRequired(), "Expected one-shot duration millis"); + int amplitude = hasAmplitude + ? parseInt(getNextArgRequired(), "Expected one-shot amplitude") : VibrationEffect.DEFAULT_AMPLITUDE; composition.addOffDuration(Duration.ofMillis(delay)); composition.addEffect(VibrationEffect.createOneShot(duration, amplitude)); } + private interface EnvelopeBuilder { + void setInitialSharpness(float sharpness); + void addControlPoint(float intensity, float sharpness, long duration); + void reset(float initialSharpness); + VibrationEffect build(); + } + + private static class BasicEnveloperBuilderWrapper implements EnvelopeBuilder { + private VibrationEffect.BasicEnvelopeBuilder mBuilder = + new VibrationEffect.BasicEnvelopeBuilder(); + + @Override + public void setInitialSharpness(float sharpness) { + mBuilder.setInitialSharpness(sharpness); + } + + @Override + public void addControlPoint(float intensity, float sharpness, long duration) { + mBuilder.addControlPoint(intensity, sharpness, duration); + } + + @Override + public void reset(float initialSharpness) { + mBuilder = new VibrationEffect.BasicEnvelopeBuilder(); + mBuilder.setInitialSharpness(initialSharpness); + } + + @Override + public VibrationEffect build() { + return mBuilder.build(); + } + } + + private static class AdvancedEnveloperBuilderWrapper implements EnvelopeBuilder { + private VibrationEffect.WaveformEnvelopeBuilder mBuilder = + new VibrationEffect.WaveformEnvelopeBuilder(); + + @Override + public void setInitialSharpness(float sharpness) { + mBuilder.setInitialFrequencyHz(sharpness); + } + + @Override + public void addControlPoint(float intensity, float sharpness, long duration) { + mBuilder.addControlPoint(intensity, sharpness, duration); + } + + @Override + public void reset(float initialSharpness) { + mBuilder = new VibrationEffect.WaveformEnvelopeBuilder(); + mBuilder.setInitialFrequencyHz(initialSharpness); + } + + @Override + public VibrationEffect build() { + return mBuilder.build(); + } + } + + private void addEnvelopeToComposition(VibrationEffect.Composition composition) { + getNextArgRequired(); // consume "envelope" + int repeat = -1; + float initialSharpness = Float.NaN; + VibrationEffect preamble = null; + boolean isAdvanced = false; + String nextOption; + while ((nextOption = getNextOption()) != null) { + switch (nextOption) { + case "-a" -> isAdvanced = true; + case "-i" -> initialSharpness = parseFloat(getNextArgRequired(), + "Expected initial sharpness after -i"); + case "-r" -> repeat = parseInt(getNextArgRequired(), + "Expected repeat index after -r"); + } + } + + EnvelopeBuilder builder = isAdvanced ? new AdvancedEnveloperBuilderWrapper() + : new BasicEnveloperBuilderWrapper(); + + if (!Float.isNaN(initialSharpness)) { + builder.setInitialSharpness(initialSharpness); + } + + int duration, pos = 0; + float intensity, sharpness = 0f; + String nextArg; + while ((nextArg = peekNextArg()) != null) { + if (pos > 0 && pos == repeat) { + preamble = builder.build(); + builder.reset(sharpness); + } + try { + duration = Integer.parseInt(nextArg); + getNextArgRequired(); // consume the duration + } catch (NumberFormatException e) { + // nextArg is not a duration, finish reading. + break; + } + intensity = parseFloat(getNextArgRequired(), "Expected envelope intensity"); + sharpness = parseFloat(getNextArgRequired(), "Expected envelope sharpness"); + builder.addControlPoint(intensity, sharpness, duration); + pos++; + } + + if (repeat >= 0) { + if (preamble == null) { + composition.addEffect(VibrationEffect.createRepeatingEffect(builder.build())); + } else { + composition.addEffect( + VibrationEffect.createRepeatingEffect(preamble, builder.build())); + } + return; + } + + composition.addEffect(builder.build()); + } + private void addWaveformToComposition(VibrationEffect.Composition composition) { boolean hasAmplitudes = false; boolean hasFrequencies = false; @@ -2755,16 +2897,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { getNextArgRequired(); // consume "waveform" String nextOption; while ((nextOption = getNextOption()) != null) { - if ("-a".equals(nextOption)) { - hasAmplitudes = true; - } else if ("-r".equals(nextOption)) { - repeat = Integer.parseInt(getNextArgRequired()); - } else if ("-w".equals(nextOption)) { - delay = Integer.parseInt(getNextArgRequired()); - } else if ("-f".equals(nextOption)) { - hasFrequencies = true; - } else if ("-c".equals(nextOption)) { - isContinuous = true; + switch (nextOption) { + case "-a" -> hasAmplitudes = true; + case "-f" -> hasFrequencies = true; + case "-c" -> isContinuous = true; + case "-r" -> repeat = parseInt(getNextArgRequired(), + "Expected repeat index after -r"); + case "-w" -> delay = parseInt(getNextArgRequired(), + "Expected delay millis after -w"); } } List<Integer> durations = new ArrayList<>(); @@ -2782,14 +2922,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { break; } if (hasAmplitudes) { - amplitudes.add( - Float.parseFloat(getNextArgRequired()) / VibrationEffect.MAX_AMPLITUDE); + int amplitude = parseInt(getNextArgRequired(), "Expected waveform amplitude"); + amplitudes.add((float) amplitude / VibrationEffect.MAX_AMPLITUDE); } else { amplitudes.add(nextAmplitude); nextAmplitude = 1 - nextAmplitude; } if (hasFrequencies) { - frequencies.add(Float.parseFloat(getNextArgRequired())); + frequencies.add( + parseFloat(getNextArgRequired(), "Expected waveform frequency")); } } @@ -2848,27 +2989,37 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { if ("-b".equals(nextOption)) { shouldFallback = true; } else if ("-w".equals(nextOption)) { - delay = Integer.parseInt(getNextArgRequired()); + delay = parseInt(getNextArgRequired(), "Expected delay millis after -w"); } } - int effectId = Integer.parseInt(getNextArgRequired()); + int effectId = parseInt(getNextArgRequired(), "Expected prebaked effect id"); composition.addOffDuration(Duration.ofMillis(delay)); composition.addEffect(VibrationEffect.get(effectId, shouldFallback)); } private void addPrimitivesToComposition(VibrationEffect.Composition composition) { getNextArgRequired(); // consume "primitives" - String nextArg; - while ((nextArg = peekNextArg()) != null) { + while (peekNextArg() != null) { int delay = 0; - if ("-w".equals(nextArg)) { - getNextArgRequired(); // consume "-w" - delay = Integer.parseInt(getNextArgRequired()); - nextArg = peekNextArg(); + float scale = 1f; + int delayType = PrimitiveSegment.DEFAULT_DELAY_TYPE; + + String nextOption; + while ((nextOption = getNextOption()) != null) { + if ("-s".equals(nextOption)) { + scale = parseFloat(getNextArgRequired(), "Expected scale after -s"); + } else if ("-o".equals(nextOption)) { + delayType = VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET; + delay = parseInt(getNextArgRequired(), "Expected offset millis after -o"); + } else if ("-w".equals(nextOption)) { + delayType = PrimitiveSegment.DEFAULT_DELAY_TYPE; + delay = parseInt(getNextArgRequired(), "Expected delay millis after -w"); + } } try { - composition.addPrimitive(Integer.parseInt(nextArg), /* scale= */ 1, delay); + String nextArg = peekNextArg(); // Just in case this is not a primitive. + composition.addPrimitive(Integer.parseInt(nextArg), scale, delay, delayType); getNextArgRequired(); // consume the primitive id } catch (NumberFormatException | NullPointerException e) { // nextArg is not describing a primitive, leave it to be consumed by outer loops @@ -2894,17 +3045,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { VibrationXmlParser.parseDocument(new StringReader(xml)); VibratorInfo combinedVibratorInfo = getCombinedVibratorInfo(); if (combinedVibratorInfo == null) { - throw new IllegalStateException( - "No combined vibrator info to parse vibration XML " + xml); + throw new IllegalStateException("No vibrator info available to parse XML"); } VibrationEffect effect = parsedVibration.resolve(combinedVibratorInfo); if (effect == null) { - throw new IllegalArgumentException( - "Parsed vibration cannot be resolved for vibration XML " + xml); + throw new IllegalArgumentException("Parsed XML cannot be resolved: " + xml); } return CombinedVibration.createParallel(effect); } catch (IOException e) { - throw new RuntimeException("Error parsing vibration XML " + xml, e); + throw new RuntimeException("Error parsing XML: " + xml, e); } } @@ -2922,16 +3071,30 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } } + private static int parseInt(String text, String errorMessage) { + try { + return Integer.parseInt(text); + } catch (NumberFormatException | NullPointerException e) { + throw new IllegalArgumentException(errorMessage, e); + } + } + + private static float parseFloat(String text, String errorMessage) { + try { + return Float.parseFloat(text); + } catch (NumberFormatException | NullPointerException e) { + throw new IllegalArgumentException(errorMessage, e); + } + } + @Override public void onHelp() { try (PrintWriter pw = getOutPrintWriter();) { pw.println("Vibrator Manager commands:"); pw.println(" help"); pw.println(" Prints this help text."); - pw.println(""); pw.println(" list"); - pw.println(" Prints the id of device vibrators. This does not include any "); - pw.println(" connected input device."); + pw.println(" Prints device vibrator ids; does not include input devices."); pw.println(" synced [options] <effect>..."); pw.println(" Vibrates effect on all vibrators in sync."); pw.println(" combined [options] (-v <vibrator-id> <effect>...)..."); @@ -2941,58 +3104,63 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { pw.println(" xml [options] <xml>"); pw.println(" Vibrates using combined vibration described in given XML string"); pw.println(" on all vibrators in sync. The XML could be:"); - pw.println(" XML containing a single effect, or"); - pw.println(" A vibration select XML containing multiple effects."); - pw.println(" Vibrates using combined vibration described in given XML string."); - pw.println(" XML containing a single effect it runs on all vibrators in sync."); + pw.println(" A single <vibration-effect>, or"); + pw.println(" A <vibration-select> containing multiple effects."); + pw.println(" feedback [options] <constant>"); + pw.println(" Performs a haptic feedback with the given constant."); pw.println(" cancel"); pw.println(" Cancels any active vibration"); - pw.println(" feedback [-f] [-d <description>] <constant>"); - pw.println(" Performs a haptic feedback with the given constant."); - pw.println(" The force (-f) option enables the `always` configuration, which"); - pw.println(" plays the haptic irrespective of the vibration intensity settings"); pw.println(""); pw.println("Effect commands:"); pw.println(" oneshot [-w delay] [-a] <duration> [<amplitude>]"); - pw.println(" Vibrates for duration milliseconds; ignored when device is on "); - pw.println(" DND (Do Not Disturb) mode; touch feedback strength user setting "); - pw.println(" will be used to scale amplitude."); + pw.println(" Vibrates for duration milliseconds."); pw.println(" If -w is provided, the effect will be played after the specified"); pw.println(" wait time in milliseconds."); pw.println(" If -a is provided, the command accepts a second argument for "); pw.println(" amplitude, in a scale of 1-255."); pw.print(" waveform [-w delay] [-r index] [-a] [-f] [-c] "); pw.println("(<duration> [<amplitude>] [<frequency>])..."); - pw.println(" Vibrates for durations and amplitudes in list; ignored when "); - pw.println(" device is on DND (Do Not Disturb) mode; touch feedback strength "); - pw.println(" user setting will be used to scale amplitude."); + pw.println(" Vibrates for durations and amplitudes in list."); pw.println(" If -w is provided, the effect will be played after the specified"); pw.println(" wait time in milliseconds."); pw.println(" If -r is provided, the waveform loops back to the specified"); - pw.println(" index (e.g. 0 loops from the beginning)"); + pw.println(" index (e.g. 0 loops from the beginning)."); pw.println(" If -a is provided, the command expects amplitude to follow each"); pw.println(" duration; otherwise, it accepts durations only and alternates"); - pw.println(" off/on"); + pw.println(" off/on."); pw.println(" If -f is provided, the command expects frequency to follow each"); - pw.println(" amplitude or duration; otherwise, it uses resonant frequency"); + pw.println(" amplitude or duration; otherwise, it uses resonant frequency."); pw.println(" If -c is provided, the waveform is continuous and will ramp"); pw.println(" between values; otherwise each entry is a fixed step."); pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255;"); - pw.println(" frequency is an absolute value in hertz;"); + pw.println(" frequency is an absolute value in hertz."); + pw.print(" envelope [-a] [-i initial sharpness] [-r index] "); + pw.println("[<duration1> <intensity1> <sharpness1>]..."); + pw.println(" Generates a vibration pattern based on a series of duration, "); + pw.println(" intensity, and sharpness values. The total vibration time is "); + pw.println(" the sum of all durations."); + pw.println(" If -a is provided, the waveform will use the advanced APIs to "); + pw.println(" generate the vibration pattern and the input parameters "); + pw.println(" become [<duration1> <amplitude1> <frequency1>]."); + pw.println(" If -i is provided, the waveform will have an initial sharpness "); + pw.println(" it will start from."); + pw.println(" If -r is provided, the waveform loops back to the specified index"); + pw.println(" (e.g. 0 loops from the beginning)."); pw.println(" prebaked [-w delay] [-b] <effect-id>"); - pw.println(" Vibrates with prebaked effect; ignored when device is on DND "); - pw.println(" (Do Not Disturb) mode; touch feedback strength user setting "); - pw.println(" will be used to scale amplitude."); + pw.println(" Vibrates with prebaked effect."); pw.println(" If -w is provided, the effect will be played after the specified"); pw.println(" wait time in milliseconds."); pw.println(" If -b is provided, the prebaked fallback effect will be played if"); pw.println(" the device doesn't support the given effect-id."); - pw.println(" primitives ([-w delay] <primitive-id>)..."); - pw.println(" Vibrates with a composed effect; ignored when device is on DND "); - pw.println(" (Do Not Disturb) mode; touch feedback strength user setting "); - pw.println(" will be used to scale primitive intensities."); + pw.print(" primitives ([-w delay] [-o time] [-s scale]"); + pw.println("<primitive-id> [<scale>])..."); + pw.println(" Vibrates with a composed effect."); pw.println(" If -w is provided, the next primitive will be played after the "); pw.println(" specified wait time in milliseconds."); + pw.println(" If -o is provided, the next primitive will be played at the "); + pw.println(" specified start offset time in milliseconds."); + pw.println(" If -s is provided, the next primitive will be played with the"); + pw.println(" specified amplitude scale, in a scale of [0,1]."); pw.println(""); pw.println("Common Options:"); pw.println(" -f"); @@ -3003,6 +3171,11 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { pw.println(" -d <description>"); pw.println(" Add description to the vibration."); pw.println(""); + pw.println("Notes"); + pw.println(" Vibrations triggered by these commands will be ignored when"); + pw.println(" device is on DND (Do Not Disturb) mode; notification strength"); + pw.println(" user settings will be applied for scale."); + pw.println(""); } } } diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 6cc17d4fa009..a94183849bc5 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -857,8 +857,7 @@ class ActivityMetricsLogger { info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs); info.mIsDrawn = true; final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info); - if (info.mLoggedTransitionStarting || (!r.mDisplayContent.mOpeningApps.contains(r) - && !r.mTransitionController.isCollecting(r))) { + if (info.mLoggedTransitionStarting || !r.mTransitionController.isCollecting(r)) { done(false /* abort */, info, "notifyWindowsDrawn", timestampNs); } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index c37b5a055140..7b6d408fbe2c 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -109,7 +109,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED; import static android.view.WindowManager.PROPERTY_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING_STATE_SHARING; -import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_UNSET; import static android.view.WindowManager.TRANSIT_RELAUNCH; import static android.view.WindowManager.hasWindowExtensionsEnabled; @@ -159,7 +158,6 @@ import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK; import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE; import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING; import static com.android.server.wm.ActivityRecordProto.IS_USER_FULLSCREEN_OVERRIDE_ENABLED; -import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN; import static com.android.server.wm.ActivityRecordProto.LAST_DROP_INPUT_MODE; import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING; @@ -290,6 +288,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.UserProperties; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.PixelFormat; @@ -321,16 +320,13 @@ import android.util.MergedConfiguration; import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; -import android.view.AppTransitionAnimationSpec; import android.view.DisplayInfo; -import android.view.IAppTransitionAnimationSpecsFuture; import android.view.InputApplicationHandle; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets; -import android.view.WindowInsets.Type; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.TransitionOldType; @@ -354,7 +350,6 @@ import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; import com.android.internal.os.TimeoutRecord; import com.android.internal.os.TransferPipe; -import com.android.internal.policy.AttributeCache; import com.android.internal.policy.PhoneWindow; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.XmlUtils; @@ -481,6 +476,8 @@ final class ActivityRecord extends WindowToken { final String processName; // process where this component wants to run final String taskAffinity; // as per ActivityInfo.taskAffinity final boolean stateNotNeeded; // As per ActivityInfo.flags + @Nullable + final WindowStyle mWindowStyle; @VisibleForTesting int mHandoverLaunchDisplayId = INVALID_DISPLAY; // Handover launch display id to next activity. @VisibleForTesting @@ -493,6 +490,7 @@ final class ActivityRecord extends WindowToken { private long createTime = System.currentTimeMillis(); long lastVisibleTime; // last time this activity became visible long pauseTime; // last time we started pausing the activity + long mStoppedTime; // last time we completely stopped the activity long launchTickTime; // base time for launch tick messages long topResumedStateLossTime; // last time we reported top resumed state loss to an activity // Last configuration reported to the activity in the client process. @@ -1519,17 +1517,7 @@ final class ActivityRecord extends WindowToken { this.task = newTask; if (shouldStartChangeTransition(newParent, oldParent)) { - if (mTransitionController.isShellTransitionsEnabled()) { - // For Shell transition, call #initializeChangeTransition directly to take the - // screenshot at the Activity level. And Shell will be in charge of handling the - // surface reparent and crop. - initializeChangeTransition(getBounds()); - } else { - // For legacy app transition, we want to take a screenshot of the Activity surface, - // but animate the change transition on TaskFragment level to get the correct window - // crop. - newParent.initializeChangeTransition(getBounds(), getSurfaceControl()); - } + mTransitionController.collectVisibleChange(this); } super.onParentChanged(newParent, oldParent); @@ -1557,16 +1545,6 @@ final class ActivityRecord extends WindowToken { mLastReportedPictureInPictureMode = inPinnedWindowingMode(); } - // When the associated task is {@code null}, the {@link ActivityRecord} can no longer - // access visual elements like the {@link DisplayContent}. We must remove any associations - // such as animations. - if (task == null) { - // It is possible we have been marked as a closing app earlier. We must remove ourselves - // from this list so we do not participate in any future animations. - if (getDisplayContent() != null) { - getDisplayContent().mClosingApps.remove(this); - } - } final Task rootTask = getRootTask(); if (task == mLastParentBeforePip && task != null) { // Notify the TaskFragmentOrganizer that the activity is reparented back from pip. @@ -1749,14 +1727,6 @@ final class ActivityRecord extends WindowToken { return; } prevDc.onRunningActivityChanged(); - - if (prevDc.mOpeningApps.remove(this)) { - // Transfer opening transition to new display. - mDisplayContent.mOpeningApps.add(this); - mDisplayContent.executeAppTransition(); - } - - prevDc.mClosingApps.remove(this); prevDc.getDisplayPolicy().removeRelaunchingApp(this); if (prevDc.mFocusedApp == this) { @@ -1956,22 +1926,17 @@ final class ActivityRecord extends WindowToken { ? android.R.style.Theme : android.R.style.Theme_Holo; } - final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, - realTheme, com.android.internal.R.styleable.Window, mUserId); - - if (ent != null) { - final boolean styleTranslucent = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsTranslucent, false); - final boolean styleFloating = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsFloating, false); - mOccludesParent = !(styleTranslucent || styleFloating) + final WindowStyle style = mAtmService.getWindowStyle(packageName, realTheme, mUserId); + mWindowStyle = style; + if (style != null) { + mOccludesParent = !(style.isTranslucent() || style.isFloating()) // This style is propagated to the main window attributes with // FLAG_SHOW_WALLPAPER from PhoneWindow#generateLayout. - || ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false); + || style.showWallpaper(); mStyleFillsParent = mOccludesParent; - mNoDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); - mOptOutEdgeToEdge = PhoneWindow.isOptingOutEdgeToEdgeEnforcement( - aInfo.applicationInfo, false /* local */, ent.array); + mNoDisplay = style.noDisplay(); + mOptOutEdgeToEdge = style.optOutEdgeToEdge() && PhoneWindow.isOptOutEdgeToEdgeEnabled( + aInfo.applicationInfo, false /* local */); } else { mStyleFillsParent = mOccludesParent = true; mNoDisplay = false; @@ -2302,21 +2267,17 @@ final class ActivityRecord extends WindowToken { return false; } - final AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, - com.android.internal.R.styleable.Window, mWmService.mCurrentUserId); - if (ent == null) { + final WindowStyle style = theme == this.theme + ? mWindowStyle : mAtmService.getWindowStyle(pkg, theme, mUserId); + if (style == null) { // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't // see that. return false; } - final boolean windowIsTranslucent = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsTranslucent, false); - final boolean windowIsFloating = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowIsFloating, false); - final boolean windowShowWallpaper = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowShowWallpaper, false); - final boolean windowDisableStarting = ent.array.getBoolean( - com.android.internal.R.styleable.Window_windowDisablePreview, false); + final boolean windowIsTranslucent = style.isTranslucent(); + final boolean windowIsFloating = style.isFloating(); + final boolean windowShowWallpaper = style.showWallpaper(); + final boolean windowDisableStarting = style.disablePreview(); ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s", windowIsTranslucent, windowIsFloating, windowShowWallpaper, @@ -2385,7 +2346,8 @@ final class ActivityRecord extends WindowToken { // The snapshot of home is only used once because it won't be updated while screen // is on (see {@link TaskSnapshotController#screenTurningOff}). mWmService.mTaskSnapshotController.removeSnapshotCache(task.mTaskId); - if ((mDisplayContent.mAppTransition.getTransitFlags() + final Transition transition = mTransitionController.getCollectingTransition(); + if (transition != null && (transition.getFlags() & WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) { // Only use snapshot of home as starting window when unlocking directly. return false; @@ -3674,7 +3636,6 @@ final class ActivityRecord extends WindowToken { if (DEBUG_VISIBILITY || DEBUG_TRANSITION) { Slog.v(TAG_TRANSITION, "Prepare close transition: finishing " + this); } - mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); // When finishing the activity preemptively take the snapshot before the app window // is marked as hidden and any configuration changes take place @@ -3776,7 +3737,6 @@ final class ActivityRecord extends WindowToken { private void prepareActivityHideTransitionAnimation() { final DisplayContent dc = mDisplayContent; - dc.prepareAppTransition(TRANSIT_CLOSE); setVisibility(false); dc.executeAppTransition(); } @@ -4392,7 +4352,6 @@ final class ActivityRecord extends WindowToken { ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app token: %s", this); - getDisplayContent().mOpeningApps.remove(this); getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this); mWmService.mSnapshotController.onAppRemoved(this); mAtmService.mStartingProcessActivities.remove(this); @@ -4404,20 +4363,9 @@ final class ActivityRecord extends WindowToken { mAppCompatController.getTransparentPolicy().stop(); // Defer removal of this activity when either a child is animating, or app transition is on - // going. App transition animation might be applied on the parent task not on the activity, - // but the actual frame buffer is associated with the activity, so we have to keep the - // activity while a parent is animating. - boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN, - ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION); - if (getDisplayContent().mClosingApps.contains(this)) { - delayed = true; - } else if (getDisplayContent().mAppTransition.isTransitionSet()) { - getDisplayContent().mClosingApps.add(this); - delayed = true; - } else if (mTransitionController.inTransition()) { - delayed = true; - } - + // going. The handleCompleteDeferredRemoval will continue the removal. + final boolean delayed = isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) + || mTransitionController.inTransition(); // Don't commit visibility if it is waiting to animate. It will be set post animation. if (!delayed) { commitVisibility(false /* visible */, true /* performLayout */); @@ -4440,13 +4388,6 @@ final class ActivityRecord extends WindowToken { removeStartingWindow(); } - // If app transition animation was running for this activity, then we need to ensure that - // the app transition notifies that animations have completed in - // DisplayContent.handleAnimatingStoppedAndTransition(), so add to that list now - if (isAnimating(TRANSITION | PARENTS, ANIMATION_TYPE_APP_TRANSITION)) { - getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token); - } - if (delayed && !isEmpty()) { // set the token aside because it has an active animation to be finished ProtoLog.v(WM_DEBUG_ADD_REMOVE, @@ -5118,8 +5059,6 @@ final class ActivityRecord extends WindowToken { void applyOptionsAnimation() { if (DEBUG_TRANSITION) Slog.i(TAG, "Applying options for " + this); if (mPendingRemoteAnimation != null) { - mDisplayContent.mAppTransition.overridePendingAppTransitionRemote( - mPendingRemoteAnimation); mTransitionController.setStatusBarTransitionDelay( mPendingRemoteAnimation.getStatusBarTransitionDelay()); } else { @@ -5149,14 +5088,6 @@ final class ActivityRecord extends WindowToken { IRemoteCallback finishCallback = null; switch (animationType) { case ANIM_CUSTOM: - displayContent.mAppTransition.overridePendingAppTransition( - pendingOptions.getPackageName(), - pendingOptions.getCustomEnterResId(), - pendingOptions.getCustomExitResId(), - pendingOptions.getCustomBackgroundColor(), - pendingOptions.getAnimationStartedListener(), - pendingOptions.getAnimationFinishedListener(), - pendingOptions.getOverrideTaskTransition()); options = AnimationOptions.makeCustomAnimOptions(pendingOptions.getPackageName(), pendingOptions.getCustomEnterResId(), pendingOptions.getCustomExitResId(), pendingOptions.getCustomBackgroundColor(), @@ -5165,9 +5096,6 @@ final class ActivityRecord extends WindowToken { finishCallback = pendingOptions.getAnimationFinishedListener(); break; case ANIM_CLIP_REVEAL: - displayContent.mAppTransition.overridePendingAppTransitionClipReveal( - pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getWidth(), pendingOptions.getHeight()); options = AnimationOptions.makeClipRevealAnimOptions( pendingOptions.getStartX(), pendingOptions.getStartY(), pendingOptions.getWidth(), pendingOptions.getHeight()); @@ -5179,9 +5107,6 @@ final class ActivityRecord extends WindowToken { } break; case ANIM_SCALE_UP: - displayContent.mAppTransition.overridePendingAppTransitionScaleUp( - pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getWidth(), pendingOptions.getHeight()); options = AnimationOptions.makeScaleUpAnimOptions( pendingOptions.getStartX(), pendingOptions.getStartY(), pendingOptions.getWidth(), pendingOptions.getHeight(), @@ -5197,10 +5122,6 @@ final class ActivityRecord extends WindowToken { case ANIM_THUMBNAIL_SCALE_DOWN: final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP); final HardwareBuffer buffer = pendingOptions.getThumbnail(); - displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer, - pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getAnimationStartedListener(), - scaleUp); options = AnimationOptions.makeThumbnailAnimOptions(buffer, pendingOptions.getStartX(), pendingOptions.getStartY(), scaleUp); startCallback = pendingOptions.getAnimationStartedListener(); @@ -5213,36 +5134,9 @@ final class ActivityRecord extends WindowToken { break; case ANIM_THUMBNAIL_ASPECT_SCALE_UP: case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: - final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs(); - final IAppTransitionAnimationSpecsFuture specsFuture = - pendingOptions.getSpecsFuture(); - if (specsFuture != null) { - displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture( - specsFuture, pendingOptions.getAnimationStartedListener(), - animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP); - } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN - && specs != null) { - displayContent.mAppTransition.overridePendingAppTransitionMultiThumb( - specs, pendingOptions.getAnimationStartedListener(), - pendingOptions.getAnimationFinishedListener(), false); - } else { - displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb( - pendingOptions.getThumbnail(), - pendingOptions.getStartX(), pendingOptions.getStartY(), - pendingOptions.getWidth(), pendingOptions.getHeight(), - pendingOptions.getAnimationStartedListener(), - (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP)); - if (intent.getSourceBounds() == null) { - intent.setSourceBounds(new Rect(pendingOptions.getStartX(), - pendingOptions.getStartY(), - pendingOptions.getStartX() + pendingOptions.getWidth(), - pendingOptions.getStartY() + pendingOptions.getHeight())); - } - } + // TODO(b/397847511): remove the related types from ActivityOptions. break; case ANIM_OPEN_CROSS_PROFILE_APPS: - displayContent.mAppTransition - .overridePendingAppTransitionStartCrossProfileApps(); options = AnimationOptions.makeCrossProfileAnimOptions(); break; case ANIM_NONE: @@ -5499,8 +5393,6 @@ final class ActivityRecord extends WindowToken { } private void setVisibility(boolean visible, boolean deferHidingClient) { - final AppTransition appTransition = getDisplayContent().mAppTransition; - // Don't set visibility to false if we were already not visible. This prevents WM from // adding the app to the closing app list which doesn't make sense for something that is // already not visible. However, set visibility to true even if we are already visible. @@ -5520,8 +5412,8 @@ final class ActivityRecord extends WindowToken { } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", - token, visible, appTransition, isVisible(), mVisibleRequested, + "setAppVisibility(%s, visible=%b): visible=%b mVisibleRequested=%b Callers=%s", + token, visible, isVisible(), mVisibleRequested, Debug.getCallers(6)); // Before setting mVisibleRequested so we can track changes. @@ -5552,9 +5444,6 @@ final class ActivityRecord extends WindowToken { mAtmService.mBackNavigationController.onAppVisibilityChanged(this, visible); - final DisplayContent displayContent = getDisplayContent(); - displayContent.mOpeningApps.remove(this); - displayContent.mClosingApps.remove(this); setVisibleRequested(visible); mLastDeferHidingClient = deferHidingClient; @@ -5567,13 +5456,6 @@ final class ActivityRecord extends WindowToken { setClientVisible(false); } } else { - if (!appTransition.isTransitionSet() - && appTransition.isReady()) { - // Add the app mOpeningApps if transition is unset but ready. This means - // we're doing a screen freeze, and the unfreeze will wait for all opening - // apps to be ready. - displayContent.mOpeningApps.add(this); - } startingMoved = false; // If the token is currently hidden (should be the common case), or has been // stopped, then we need to set up to wait for its windows to be ready. @@ -5628,15 +5510,6 @@ final class ActivityRecord extends WindowToken { updateReportedVisibilityLocked(); } - @Override - boolean applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter, - boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) { - if ((mTransitionChangeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { - return false; - } - return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources); - } - /** * Update visibility to this {@link ActivityRecord}. * @@ -6506,6 +6379,7 @@ final class ActivityRecord extends WindowToken { Slog.w(TAG, "Exception thrown during pause", e); // Just in case, assume it to be stopped. mAppStopped = true; + mStoppedTime = SystemClock.uptimeMillis(); ProtoLog.v(WM_DEBUG_STATES, "Stop failed; moving to STOPPED: %s", this); setState(STOPPED, "stopIfPossible"); } @@ -6539,6 +6413,7 @@ final class ActivityRecord extends WindowToken { if (isStopping) { ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPED: %s (stop complete)", this); + mStoppedTime = SystemClock.uptimeMillis(); setState(STOPPED, "activityStopped"); } @@ -6698,9 +6573,7 @@ final class ActivityRecord extends WindowToken { // starting window is drawn, the transition can start earlier. Exclude finishing and bubble // because it may be a trampoline. if (app == null && !finishing && !mLaunchedFromBubble - && mVisibleRequested && !mDisplayContent.mAppTransition.isReady() - && !mDisplayContent.mAppTransition.isRunning() - && mDisplayContent.isNextTransitionForward()) { + && mVisibleRequested && mDisplayContent.isNextTransitionForward()) { // The pending transition state will be cleared after the transition is started, so // save the state for launching the client later (used by LaunchActivityItem). mStartingData.mIsTransitionForward = true; @@ -6775,7 +6648,7 @@ final class ActivityRecord extends WindowToken { setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow"); // We can now show all of the drawn windows! - if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) { + if (canShowWindows()) { showAllWindowsLocked(); } } @@ -7187,14 +7060,10 @@ final class ActivityRecord extends WindowToken { if (theme == 0) { return false; } - final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, theme, - R.styleable.Window, mWmService.mCurrentUserId); - if (ent != null) { - if (ent.array.hasValue(R.styleable.Window_windowSplashScreenBehavior)) { - return ent.array.getInt(R.styleable.Window_windowSplashScreenBehavior, - SPLASH_SCREEN_BEHAVIOR_DEFAULT) - == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED; - } + final WindowStyle style = theme == this.theme + ? mWindowStyle : mAtmService.getWindowStyle(packageName, theme, mUserId); + if (style != null) { + return style.mSplashScreenBehavior == SPLASH_SCREEN_BEHAVIOR_ICON_PREFERRED; } return false; } @@ -7449,15 +7318,6 @@ final class ActivityRecord extends WindowToken { return boundsLayer; } - @Override - boolean isWaitingForTransitionStart() { - final DisplayContent dc = getDisplayContent(); - return dc != null && dc.mAppTransition.isTransitionSet() - && (dc.mOpeningApps.contains(this) - || dc.mClosingApps.contains(this) - || dc.mChangingContainers.contains(this)); - } - boolean isTransitionForward() { return (mStartingData != null && mStartingData.mIsTransitionForward) || mDisplayContent.isNextTransitionForward(); @@ -7595,7 +7455,6 @@ final class ActivityRecord extends WindowToken { } } - getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token); scheduleAnimation(); // Schedule to handle the stopping and finishing activities which the animation is done @@ -9561,7 +9420,6 @@ final class ActivityRecord extends WindowToken { writeNameToProto(proto, NAME); super.dumpDebug(proto, WINDOW_TOKEN, logLevel); proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing); - proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart()); proto.write(IS_ANIMATING, isAnimating(TRANSITION | PARENTS | CHILDREN, ANIMATION_TYPE_APP_TRANSITION | ANIMATION_TYPE_WINDOW_ANIMATION)); proto.write(FILLS_PARENT, fillsParent()); @@ -9717,7 +9575,18 @@ final class ActivityRecord extends WindowToken { && !mDisplayContent.isSleeping()) { // Visibility of starting activities isn't calculated until pause-complete, so if // this is not paused yet, don't consider it ready. - return false; + // However, due to pip1 having an intermediate state, add a special exception here + // that skips waiting if the next activity is already visible. + final ActivityRecord toResume = isPip2ExperimentEnabled() ? null + : mDisplayContent.getActivity((r) -> !r.finishing + && r.isVisibleRequested() + && !r.isTaskOverlay() + && !r.isAlwaysOnTop()); + if (toResume == null || !toResume.isVisible()) { + return false; + } else { + Slog.i(TAG, "Assuming sync-finish while pausing due to visible target"); + } } return true; } @@ -9876,6 +9745,68 @@ final class ActivityRecord extends WindowToken { int mBackgroundColor; } + static class WindowStyle { + private static final int FLAG_IS_TRANSLUCENT = 1; + private static final int FLAG_IS_FLOATING = 1 << 1; + private static final int FLAG_SHOW_WALLPAPER = 1 << 2; + private static final int FLAG_NO_DISPLAY = 1 << 3; + private static final int FLAG_DISABLE_PREVIEW = 1 << 4; + private static final int FLAG_OPT_OUT_EDGE_TO_EDGE = 1 << 5; + + final int mFlags; + + @SplashScreenBehavior + final int mSplashScreenBehavior; + + WindowStyle(TypedArray array) { + int flags = 0; + if (array.getBoolean(R.styleable.Window_windowIsTranslucent, false)) { + flags |= FLAG_IS_TRANSLUCENT; + } + if (array.getBoolean(R.styleable.Window_windowIsFloating, false)) { + flags |= FLAG_IS_FLOATING; + } + if (array.getBoolean(R.styleable.Window_windowShowWallpaper, false)) { + flags |= FLAG_SHOW_WALLPAPER; + } + if (array.getBoolean(R.styleable.Window_windowNoDisplay, false)) { + flags |= FLAG_NO_DISPLAY; + } + if (array.getBoolean(R.styleable.Window_windowDisablePreview, false)) { + flags |= FLAG_DISABLE_PREVIEW; + } + if (array.getBoolean(R.styleable.Window_windowOptOutEdgeToEdgeEnforcement, false)) { + flags |= FLAG_OPT_OUT_EDGE_TO_EDGE; + } + mFlags = flags; + mSplashScreenBehavior = array.getInt(R.styleable.Window_windowSplashScreenBehavior, 0); + } + + boolean isTranslucent() { + return (mFlags & FLAG_IS_TRANSLUCENT) != 0; + } + + boolean isFloating() { + return (mFlags & FLAG_IS_FLOATING) != 0; + } + + boolean showWallpaper() { + return (mFlags & FLAG_SHOW_WALLPAPER) != 0; + } + + boolean noDisplay() { + return (mFlags & FLAG_NO_DISPLAY) != 0; + } + + boolean disablePreview() { + return (mFlags & FLAG_DISABLE_PREVIEW) != 0; + } + + boolean optOutEdgeToEdge() { + return (mFlags & FLAG_OPT_OUT_EDGE_TO_EDGE) != 0; + } + } + static class Builder { private final ActivityTaskManagerService mAtmService; private WindowProcessController mCallerApp; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 0a57cb50d681..c243cdc23137 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -617,6 +617,9 @@ public abstract class ActivityTaskManagerInternal { */ public abstract boolean isBaseOfLockedTask(String packageName); + /** Returns the value of {@link android.R.attr#windowNoDisplay} from the given theme. */ + public abstract boolean isNoDisplay(String packageName, int theme, int userId); + /** * Creates an interface to update configuration for the calling application. */ diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 819e117e6d05..6f83822ee97a 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -286,6 +286,7 @@ import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; +import com.android.server.wm.utils.WindowStyleCache; import com.android.wm.shell.Flags; import java.io.BufferedReader; @@ -500,6 +501,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { boolean mSuppressResizeConfigChanges; + private final WindowStyleCache<ActivityRecord.WindowStyle> mWindowStyleCache = + new WindowStyleCache<>(ActivityRecord.WindowStyle::new); final UpdateConfigurationResult mTmpUpdateConfigurationResult = new UpdateConfigurationResult(); @@ -2127,6 +2130,26 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public boolean setTaskIsPerceptible(int taskId, boolean isPerceptible) { + enforceTaskPermission("setTaskIsPerceptible()"); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + final Task task = mRootWindowContainer.anyTaskForId(taskId, + MATCH_ATTACHED_TASK_ONLY); + if (task == null) { + Slog.w(TAG, "setTaskIsPerceptible: No task to set with id=" + taskId); + return false; + } + task.mIsPerceptible = isPerceptible; + } + return true; + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override public boolean removeTask(int taskId) { mAmInternal.enforceCallingPermission(REMOVE_TASKS, "removeTask()"); synchronized (mGlobalLock) { @@ -5570,6 +5593,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mUserManagerInternal; } + @Nullable + ActivityRecord.WindowStyle getWindowStyle(String packageName, int theme, int userId) { + if (!com.android.window.flags.Flags.cacheWindowStyle()) { + final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, + theme, com.android.internal.R.styleable.Window, userId); + return ent != null ? new ActivityRecord.WindowStyle(ent.array) : null; + } + return mWindowStyleCache.get(packageName, theme, userId); + } + AppWarnings getAppWarningsLocked() { return mAppWarnings; } @@ -6518,6 +6551,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mCompatModePackages.handlePackageUninstalledLocked(name); mPackageConfigPersister.onPackageUninstall(name, userId); } + mWindowStyleCache.invalidatePackage(name); } @Override @@ -6534,6 +6568,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (mRootWindowContainer == null) return; mRootWindowContainer.updateActivityApplicationInfo(aInfo); } + mWindowStyleCache.invalidatePackage(aInfo.packageName); } @Override @@ -7433,6 +7468,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override + public boolean isNoDisplay(String packageName, int theme, int userId) { + if (!com.android.window.flags.Flags.cacheWindowStyle()) { + final AttributeCache.Entry ent = AttributeCache.instance() + .get(packageName, theme, R.styleable.Window, userId); + return ent != null + && ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); + } + final ActivityRecord.WindowStyle style = getWindowStyle(packageName, theme, userId); + return style != null && style.noDisplay(); + } + + @Override public PackageConfigurationUpdater createPackageConfigurationUpdater() { return new PackageConfigurationUpdaterImpl(Binder.getCallingPid(), ActivityTaskManagerService.this); diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index b607b0fce9ab..463a92fb55bb 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -900,108 +900,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { lockTaskController.startLockTaskMode(task, false, 0 /* blank UID */); } - try { - if (!proc.hasThread()) { - throw new RemoteException(); - } - List<ResultInfo> results = null; - List<ReferrerIntent> newIntents = null; - if (andResume) { - // We don't need to deliver new intents and/or set results if activity is going - // to pause immediately after launch. - results = r.results; - newIntents = r.newIntents; - } - if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, - "Launching: " + r + " savedState=" + r.getSavedState() - + " with results=" + results + " newIntents=" + newIntents - + " andResume=" + andResume); - EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r), - task.mTaskId, r.shortComponentName); - updateHomeProcessIfNeeded(r); - mService.getPackageManagerInternalLocked().notifyPackageUse( - r.intent.getComponent().getPackageName(), NOTIFY_PACKAGE_USE_ACTIVITY); - mService.getAppWarningsLocked().onStartActivity(r); - - final Configuration procConfig = proc.prepareConfigurationForLaunchingActivity(); - final Configuration overrideConfig = r.getMergedOverrideConfiguration(); - r.setLastReportedConfiguration(procConfig, overrideConfig); - - final ActivityWindowInfo activityWindowInfo = r.getActivityWindowInfo(); - r.setLastReportedActivityWindowInfo(activityWindowInfo); - - logIfTransactionTooLarge(r.intent, r.getSavedState()); - - final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment(); - if (organizedTaskFragment != null) { - // Sending TaskFragmentInfo to client to ensure the info is updated before - // the activity creation. - mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent( - organizedTaskFragment); - } - - // Create activity launch transaction. - final boolean isTransitionForward = r.isTransitionForward(); - final IBinder fragmentToken = r.getTaskFragment().getFragmentToken(); - final int deviceId = getDeviceIdForDisplayId(r.getDisplayId()); - final LaunchActivityItem launchActivityItem = new LaunchActivityItem(r.token, - r.intent, System.identityHashCode(r), r.info, - procConfig, overrideConfig, deviceId, - r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor, - proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(), - results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward, - proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, - r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken, - r.initialCallerInfoAccessToken, activityWindowInfo); - - // Set desired final state. - final ActivityLifecycleItem lifecycleItem; - if (andResume) { - lifecycleItem = new ResumeActivityItem(r.token, isTransitionForward, - r.shouldSendCompatFakeFocus()); - } else if (r.isVisibleRequested()) { - lifecycleItem = new PauseActivityItem(r.token); - } else { - lifecycleItem = new StopActivityItem(r.token); - } - - // Schedule transaction. - if (shouldDispatchLaunchActivityItemIndependently(r.info.packageName, r.getUid())) { - // LaunchActivityItem has @UnsupportedAppUsage usages. - // Guard with targetSDK on Android 15+. - // To not bundle the transaction, dispatch the pending before schedule new - // transaction. - mService.getLifecycleManager().dispatchPendingTransaction(proc.getThread()); - } - mService.getLifecycleManager().scheduleTransactionItems( - proc.getThread(), - // Immediately dispatch the transaction, so that if it fails, the server can - // restart the process and retry now. - true /* shouldDispatchImmediately */, - launchActivityItem, lifecycleItem); - - if (procConfig.seq > mRootWindowContainer.getConfiguration().seq) { - // If the seq is increased, there should be something changed (e.g. registered - // activity configuration). - proc.setLastReportedConfiguration(procConfig); - } - if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0 - && mService.mHasHeavyWeightFeature) { - // This may be a heavy-weight process! Note that the package manager will ensure - // that only activity can run in the main process of the .apk, which is the only - // thing that will be considered heavy-weight. - if (proc.mName.equals(proc.mInfo.packageName)) { - if (mService.mHeavyWeightProcess != null - && mService.mHeavyWeightProcess != proc) { - Slog.w(TAG, "Starting new heavy weight process " + proc - + " when already running " - + mService.mHeavyWeightProcess); - } - mService.setHeavyWeightProcess(r); - } - } - - } catch (RemoteException e) { + final RemoteException e = tryRealStartActivityInner( + task, r, proc, activityClientController, andResume); + if (e != null) { if (r.launchFailed) { // This is the second time we failed -- finish activity and give up. Slog.e(TAG, "Second failure launching " @@ -1024,7 +925,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { r.launchFailed = false; - // TODO(lifecycler): Resume or pause requests are done as part of launch transaction, + // Resume or pause requests are done as part of launch transaction, // so updating the state should be done accordingly. if (andResume && readyToResume()) { // As part of the process of launching, ActivityThread also performs @@ -1064,6 +965,122 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { return true; } + /** @return {@link RemoteException} if the app process failed to handle the activity start. */ + @Nullable + private RemoteException tryRealStartActivityInner( + @NonNull Task task, + @NonNull ActivityRecord r, + @NonNull WindowProcessController proc, + @Nullable IActivityClientController activityClientController, + boolean andResume) { + if (!proc.hasThread()) { + return new RemoteException(); + } + List<ResultInfo> results = null; + List<ReferrerIntent> newIntents = null; + if (andResume) { + // We don't need to deliver new intents and/or set results if activity is going + // to pause immediately after launch. + results = r.results; + newIntents = r.newIntents; + } + if (DEBUG_SWITCH) { + Slog.v(TAG_SWITCH, + "Launching: " + r + " savedState=" + r.getSavedState() + + " with results=" + results + " newIntents=" + newIntents + + " andResume=" + andResume); + } + EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r), + task.mTaskId, r.shortComponentName); + updateHomeProcessIfNeeded(r); + mService.getPackageManagerInternalLocked().notifyPackageUse( + r.intent.getComponent().getPackageName(), NOTIFY_PACKAGE_USE_ACTIVITY); + mService.getAppWarningsLocked().onStartActivity(r); + + final Configuration procConfig = proc.prepareConfigurationForLaunchingActivity(); + final Configuration overrideConfig = r.getMergedOverrideConfiguration(); + r.setLastReportedConfiguration(procConfig, overrideConfig); + + final ActivityWindowInfo activityWindowInfo = r.getActivityWindowInfo(); + r.setLastReportedActivityWindowInfo(activityWindowInfo); + + logIfTransactionTooLarge(r.intent, r.getSavedState()); + + final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment(); + if (organizedTaskFragment != null) { + // Sending TaskFragmentInfo to client to ensure the info is updated before + // the activity creation. + mService.mTaskFragmentOrganizerController.dispatchPendingInfoChangedEvent( + organizedTaskFragment); + } + + // Create activity launch transaction. + final boolean isTransitionForward = r.isTransitionForward(); + final IBinder fragmentToken = r.getTaskFragment().getFragmentToken(); + final int deviceId = getDeviceIdForDisplayId(r.getDisplayId()); + final LaunchActivityItem launchActivityItem = new LaunchActivityItem(r.token, + r.intent, System.identityHashCode(r), r.info, + procConfig, overrideConfig, deviceId, + r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor, + proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(), + results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward, + proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, + r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken, + r.initialCallerInfoAccessToken, activityWindowInfo); + + // Set desired final state. + final ActivityLifecycleItem lifecycleItem; + if (andResume) { + lifecycleItem = new ResumeActivityItem(r.token, isTransitionForward, + r.shouldSendCompatFakeFocus()); + } else if (r.isVisibleRequested()) { + lifecycleItem = new PauseActivityItem(r.token); + } else { + lifecycleItem = new StopActivityItem(r.token); + } + + // Schedule transaction. + if (shouldDispatchLaunchActivityItemIndependently(r.info.packageName, r.getUid())) { + // LaunchActivityItem has @UnsupportedAppUsage usages. + // Guard with targetSDK on Android 15+. + // To not bundle the transaction, dispatch the pending before schedule new + // transaction. + mService.getLifecycleManager().dispatchPendingTransaction(proc.getThread()); + } + try { + mService.getLifecycleManager().scheduleTransactionItems( + proc.getThread(), + // Immediately dispatch the transaction, so that if it fails, the server can + // restart the process and retry now. + true /* shouldDispatchImmediately */, + launchActivityItem, lifecycleItem); + } catch (RemoteException e) { + return e; + } + + if (procConfig.seq > mRootWindowContainer.getConfiguration().seq) { + // If the seq is increased, there should be something changed (e.g. registered + // activity configuration). + proc.setLastReportedConfiguration(procConfig); + } + if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0 + && mService.mHasHeavyWeightFeature) { + // This may be a heavy-weight process! Note that the package manager will ensure + // that only activity can run in the main process of the .apk, which is the only + // thing that will be considered heavy-weight. + if (proc.mName.equals(proc.mInfo.packageName)) { + if (mService.mHeavyWeightProcess != null + && mService.mHeavyWeightProcess != proc) { + Slog.w(TAG, "Starting new heavy weight process " + proc + + " when already running " + + mService.mHeavyWeightProcess); + } + mService.setHeavyWeightProcess(r); + } + } + return null; + } + void updateHomeProcessIfNeeded(@NonNull ActivityRecord r) { if (!r.isActivityTypeHome()) return; // Make sure that we use the bottom most activity from the same package, because the home diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java index dff072e2dcf8..57811e24351f 100644 --- a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java @@ -16,12 +16,14 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.window.DesktopModeFlags.EXCLUDE_CAPTION_FROM_APP_BOUNDS; import static com.android.server.wm.AppCompatConfiguration.LETTERBOX_BACKGROUND_WALLPAPER; import static com.android.server.wm.AppCompatConfiguration.letterboxBackgroundTypeToString; @@ -48,6 +50,8 @@ import java.io.PrintWriter; */ class AppCompatLetterboxPolicy { + private static final int DIFF_TOLERANCE_PX = 1; + @NonNull private final ActivityRecord mActivityRecord; @NonNull @@ -56,6 +60,9 @@ class AppCompatLetterboxPolicy { private final AppCompatRoundedCorners mAppCompatRoundedCorners; @NonNull private final AppCompatConfiguration mAppCompatConfiguration; + // Convenience temporary object to save allocation when calculating Rect. + @NonNull + private final Rect mTmpRect = new Rect(); private boolean mLastShouldShowLetterboxUi; @@ -71,7 +78,7 @@ class AppCompatLetterboxPolicy { : new LegacyLetterboxPolicyState(); // TODO (b/358334569) Improve cutout logic dependency on app compat. mAppCompatRoundedCorners = new AppCompatRoundedCorners(mActivityRecord, - this::isLetterboxedNotForDisplayCutout); + this::ieEligibleForRoundedCorners); mAppCompatConfiguration = appCompatConfiguration; } @@ -84,7 +91,7 @@ class AppCompatLetterboxPolicy { mLetterboxPolicyState.stop(); } - /** @return {@value true} if the letterbox policy is running and the activity letterboxed. */ + /** @return {@code true} if the letterbox policy is running and the activity letterboxed. */ boolean isRunning() { return mLetterboxPolicyState.isRunning(); } @@ -130,7 +137,7 @@ class AppCompatLetterboxPolicy { * <li>The activity is in fullscreen. * <li>The activity is portrait-only. * <li>The activity doesn't have a starting window (education should only be displayed - * once the starting window is removed in {@link #removeStartingWindow}). + * once the starting window is removed in {@link ActivityRecord#removeStartingWindow}). * </ul> */ boolean isEligibleForLetterboxEducation() { @@ -294,16 +301,40 @@ class AppCompatLetterboxPolicy { } } + private boolean ieEligibleForRoundedCorners(@NonNull WindowState mainWindow) { + return isLetterboxedNotForDisplayCutout(mainWindow) + && !isFreeformActivityMatchParentAppBoundsHeight(); + } + private boolean isLetterboxedNotForDisplayCutout(@NonNull WindowState mainWindow) { return shouldShowLetterboxUi(mainWindow) && !mainWindow.isLetterboxedForDisplayCutout(); } + private boolean isFreeformActivityMatchParentAppBoundsHeight() { + if (!EXCLUDE_CAPTION_FROM_APP_BOUNDS.isTrue()) { + return false; + } + final Task task = mActivityRecord.getTask(); + if (task == null) { + return false; + } + final Rect parentAppBounds = task.getWindowConfiguration().getAppBounds(); + if (parentAppBounds == null) { + return false; + } + + mLetterboxPolicyState.getLetterboxInnerBounds(mTmpRect); + final int diff = parentAppBounds.height() - mTmpRect.height(); + // Compare bounds with tolerance of 1 px to account for rounding error calculations. + return task.getWindowingMode() == WINDOWING_MODE_FREEFORM && diff <= DIFF_TOLERANCE_PX; + } + private static boolean shouldNotLayoutLetterbox(@Nullable WindowState w) { if (w == null) { return true; } - final int type = w.mAttrs.type; + final int type = w.getAttrs().type; // Allow letterbox to be displayed early for base application or application starting // windows even if it is not on the top z order to prevent flickering when the // letterboxed window is brought to the top diff --git a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java index 92d76e5616d8..8165638d4bda 100644 --- a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java +++ b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java @@ -35,12 +35,12 @@ class AppCompatRoundedCorners { @NonNull private final ActivityRecord mActivityRecord; @NonNull - private final Predicate<WindowState> mIsLetterboxedNotForDisplayCutout; + private final Predicate<WindowState> mRoundedCornersWindowCondition; AppCompatRoundedCorners(@NonNull ActivityRecord activityRecord, - @NonNull Predicate<WindowState> isLetterboxedNotForDisplayCutout) { + @NonNull Predicate<WindowState> roundedCornersWindowCondition) { mActivityRecord = activityRecord; - mIsLetterboxedNotForDisplayCutout = isLetterboxedNotForDisplayCutout; + mRoundedCornersWindowCondition = roundedCornersWindowCondition; } void updateRoundedCornersIfNeeded(@NonNull final WindowState mainWindow) { @@ -136,7 +136,7 @@ class AppCompatRoundedCorners { private boolean requiresRoundedCorners(@NonNull final WindowState mainWindow) { final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getLetterboxOverrides(); - return mIsLetterboxedNotForDisplayCutout.test(mainWindow) + return mRoundedCornersWindowCondition.test(mainWindow) && letterboxOverrides.isLetterboxActivityCornersRounded(); } diff --git a/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java b/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java index 26cf32b12d4f..6a46f57e2640 100644 --- a/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatSandboxingPolicy.java @@ -15,6 +15,8 @@ */ package com.android.server.wm; +import static android.window.DesktopModeFlags.EXCLUDE_CAPTION_FROM_APP_BOUNDS; + import static com.android.server.wm.AppCompatUtils.isInDesktopMode; import android.annotation.NonNull; @@ -22,8 +24,6 @@ import android.app.WindowConfiguration.WindowingMode; import android.content.res.Configuration; import android.graphics.Rect; -import com.android.window.flags.Flags; - /** * Encapsulate logic related to sandboxing for app compatibility. */ @@ -48,7 +48,7 @@ class AppCompatSandboxingPolicy { */ void sandboxBoundsIfNeeded(@NonNull Configuration resolvedConfig, @WindowingMode int windowingMode) { - if (!Flags.excludeCaptionFromAppBounds()) { + if (!EXCLUDE_CAPTION_FROM_APP_BOUNDS.isTrue()) { return; } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index d98ad8bb9e05..12d4a210400c 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -89,7 +89,6 @@ import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpe import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM; -import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE; import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION; @@ -1554,26 +1553,6 @@ public class AppTransition implements Dump { } private void handleAppTransitionTimeout() { - synchronized (mService.mGlobalLock) { - final DisplayContent dc = mDisplayContent; - if (dc == null) { - return; - } - notifyAppTransitionTimeoutLocked(); - if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty() - || !dc.mChangingContainers.isEmpty()) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b " - + "mOpeningApps.size()=%d mClosingApps.size()=%d " - + "mChangingApps.size()=%d", - dc.getDisplayId(), dc.mAppTransition.isTransitionSet(), - dc.mOpeningApps.size(), dc.mClosingApps.size(), - dc.mChangingContainers.size()); - - setTimeout(); - mService.mWindowPlacerLocked.performSurfacePlacement(); - } - } } private static void doAnimationCallback(@NonNull IRemoteCallback callback) { diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 094ad187686c..d652ea1e26a4 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -281,6 +281,10 @@ class BackNavigationController { } else if (hasTranslucentActivity(currentActivity, prevActivities)) { // skip if one of participant activity is translucent backType = BackNavigationInfo.TYPE_CALLBACK; + } else if (!allActivitiesHaveProcesses(prevActivities)) { + // Skip if one of previous activity has no process. Restart process can be slow, and + // the final hierarchy could be different. + backType = BackNavigationInfo.TYPE_CALLBACK; } else if (prevActivities.size() > 0 && requestOverride == SystemOverrideOnBackInvokedCallback.OVERRIDE_UNDEFINED) { if ((!isOccluded || isAllActivitiesCanShowWhenLocked(prevActivities)) @@ -603,6 +607,17 @@ class BackNavigationController { return false; } + private static boolean allActivitiesHaveProcesses( + @NonNull ArrayList<ActivityRecord> prevActivities) { + for (int i = prevActivities.size() - 1; i >= 0; --i) { + final ActivityRecord test = prevActivities.get(i); + if (!test.hasProcess()) { + return false; + } + } + return true; + } + private static boolean isAllActivitiesCanShowWhenLocked( @NonNull ArrayList<ActivityRecord> prevActivities) { for (int i = prevActivities.size() - 1; i >= 0; --i) { diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java index 05dcbb7f9af4..aaa18ad6acc9 100644 --- a/services/core/java/com/android/server/wm/ConfigurationContainer.java +++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java @@ -257,10 +257,12 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { // This should be the only place override the configuration for ActivityRecord. Override // the value if not calculated yet. Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); + Rect outConfigBounds = new Rect(outAppBounds); if (outAppBounds == null || outAppBounds.isEmpty()) { inOutConfig.windowConfiguration.setAppBounds( newParentConfiguration.windowConfiguration.getBounds()); outAppBounds = inOutConfig.windowConfiguration.getAppBounds(); + outConfigBounds.set(outAppBounds); if (task != null) { task = task.getCreatedByOrganizerTask(); if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) { @@ -279,6 +281,12 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { outAppBounds.inset(decor.mOverrideNonDecorInsets); } } + if (!outConfigBounds.intersect(decor.mOverrideConfigFrame)) { + if (inOutConfig.windowConfiguration.getWindowingMode() + == WINDOWING_MODE_MULTI_WINDOW) { + outAppBounds.inset(decor.mOverrideConfigInsets); + } + } if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) { outAppBounds.offset(-task.mOffsetXForInsets, -task.mOffsetYForInsets); } @@ -289,10 +297,10 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> { } density *= DisplayMetrics.DENSITY_DEFAULT_SCALE; if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) { - inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f); + inOutConfig.screenWidthDp = (int) (outConfigBounds.width() / density + 0.5f); } if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) { - inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f); + inOutConfig.screenHeightDp = (int) (outConfigBounds.height() / density + 0.5f); } if (inOutConfig.smallestScreenWidthDp == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) { diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java index ac987929a142..b6f74a08631e 100644 --- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java @@ -75,8 +75,8 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { return RESULT_SKIP; } if (com.android.window.flags.Flags.fixLayoutExistingTask() - && task.getOrganizedTask() != null) { - appendLog("task is organized, skipping"); + && task.getCreatedByOrganizerTask() != null) { + appendLog("has created-by-organizer-task, skipping"); return RESULT_SKIP; } @@ -111,6 +111,11 @@ class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { return RESULT_SKIP; } + if ((options == null || options.getLaunchBounds() == null) && task.hasOverrideBounds()) { + appendLog("current task has bounds set, not overriding"); + return RESULT_SKIP; + } + DesktopModeBoundsCalculator.updateInitialBounds(task, layout, activity, options, outParams.mBounds, this::appendLog); appendLog("final desktop mode task bounds set to %s", outParams.mBounds); diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index b932ef362aca..6718ae435cd9 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -748,14 +748,9 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { && policy.okToAnimate(true /* ignoreScreenOn */)) { return false; } - // Consider unoccluding only when all unknown visibilities have been - // resolved, as otherwise we just may be starting another occluding activity. - final boolean isUnoccluding = - mDisplayContent.mAppTransition.isUnoccluding() - && mDisplayContent.mUnknownAppVisibilityController.allResolved(); - // If keyguard is showing, or we're unoccluding, force the keyguard's orientation, + // Use keyguard's orientation if it is showing and not occluded // even if SystemUI hasn't updated the attrs yet. - if (policy.isKeyguardShowingAndNotOccluded() || isUnoccluding) { + if (policy.isKeyguardShowingAndNotOccluded()) { return true; } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 703ce7d24468..85416903b274 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -88,7 +88,6 @@ import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY; import static android.window.DisplayAreaOrganizer.FEATURE_IME; import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; -import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_BOOT; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_CONTENT_RECORDING; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_FOCUS; @@ -108,7 +107,6 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_W import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY; import static com.android.server.wm.DisplayContentProto.APP_TRANSITION; -import static com.android.server.wm.DisplayContentProto.CLOSING_APPS; import static com.android.server.wm.DisplayContentProto.CURRENT_FOCUS; import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES; import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO; @@ -125,7 +123,6 @@ import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_TARGET; import static com.android.server.wm.DisplayContentProto.IS_SLEEPING; import static com.android.server.wm.DisplayContentProto.KEEP_CLEAR_AREAS; import static com.android.server.wm.DisplayContentProto.MIN_SIZE_OF_RESIZEABLE_TASK_DP; -import static com.android.server.wm.DisplayContentProto.OPENING_APPS; import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY; import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA; import static com.android.server.wm.DisplayContentProto.SLEEP_TOKENS; @@ -164,6 +161,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; +import android.content.ComponentCallbacks; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; @@ -196,7 +194,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.WorkSource; import android.provider.Settings; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.DisplayUtils; @@ -367,24 +364,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final AppTransition mAppTransition; - final ArraySet<ActivityRecord> mOpeningApps = new ArraySet<>(); - final ArraySet<ActivityRecord> mClosingApps = new ArraySet<>(); - final ArraySet<WindowContainer> mChangingContainers = new ArraySet<>(); final UnknownAppVisibilityController mUnknownAppVisibilityController; - /** - * If a container is closing when resizing, keeps track of its starting bounds when it is - * removed from {@link #mChangingContainers}. - */ - final ArrayMap<WindowContainer, Rect> mClosingChangingContainers = new ArrayMap<>(); private MetricsLogger mMetricsLogger; - /** - * List of clients without a transtiton animation that we notify once we are done - * transitioning since they won't be notified through the app window animator. - */ - final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>(); - // Mapping from a token IBinder to a WindowToken object on this display. private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap(); @@ -467,6 +450,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp private DisplayInfo mLastDisplayInfoOverride; private final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); + @NonNull private final DisplayPolicy mDisplayPolicy; private final DisplayRotation mDisplayRotation; @@ -553,6 +537,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** Remove this display when animation on it has completed. */ private boolean mDeferredRemoval; + @NonNull final PinnedTaskController mPinnedTaskController; private final LinkedList<ActivityRecord> mTmpUpdateAllDrawn = new LinkedList(); @@ -1113,6 +1098,29 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp }; /** + * Called to update fields retrieve from {@link #getDisplayUiContext()} resources when + * there's a configuration update on {@link #getDisplayUiContext()}. + */ + @NonNull + private final ComponentCallbacks mSysUiContextConfigCallback = new ComponentCallbacks() { + + @Override + public void onConfigurationChanged(@NonNull Configuration newConfig) { + synchronized (mWmService.mGlobalLock) { + if (mDisplayReady) { + mDisplayPolicy.onConfigurationChanged(); + mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp(); + } + } + } + + @Override + public void onLowMemory() { + // Do nothing. + } + }; + + /** * Create new {@link DisplayContent} instance, add itself to the root window container and * initialize direct children. * @param display May not be null. @@ -1156,8 +1164,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mFixedRotationTransitionListener = new FixedRotationTransitionListener(mDisplayId); mAppTransition = new AppTransition(mWmService.mContext, mWmService, this); - mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier); - mAppTransition.registerListenerLocked(mFixedRotationTransitionListener); mTransitionController.registerLegacyListener(mFixedRotationTransitionListener); mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this); mRemoteDisplayChangeController = new RemoteDisplayChangeController(this); @@ -1910,17 +1916,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return false; } if (checkOpening) { - if (mTransitionController.isShellTransitionsEnabled()) { - if (!mTransitionController.isCollecting(r)) { - return false; - } - } else { - if (!mAppTransition.isTransitionSet() || !mOpeningApps.contains(r)) { - // Apply normal rotation animation in case of the activity set different - // requested orientation without activity switch, or the transition is unset due - // to starting window was transferred ({@link #mSkipAppTransitionAnimation}). - return false; - } + if (!mTransitionController.isCollecting(r)) { + // Apply normal rotation animation in case the activity changes requested + // orientation without activity switch. + return false; } if (r.isState(RESUMED) && !r.getTask().mInResumeTopActivity) { // If the activity is executing or has done the lifecycle callback, use normal @@ -2815,11 +2814,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp final int lastOrientation = getConfiguration().orientation; final int lastWindowingMode = getWindowingMode(); super.onConfigurationChanged(newParentConfig); - if (mDisplayPolicy != null) { - mDisplayPolicy.onConfigurationChanged(); - mPinnedTaskController.onPostDisplayConfigurationChanged(); - mMinSizeOfResizeableTaskDp = getMinimalTaskSizeDp(); + if (!Flags.trackSystemUiContextBeforeWms()) { + mSysUiContextConfigCallback.onConfigurationChanged(newParentConfig); } + mPinnedTaskController.onPostDisplayConfigurationChanged(); // Update IME parent if needed. updateImeParent(); @@ -2851,13 +2849,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp return isVisible() && !mRemoved && !mRemoving; } - @Override - void onAppTransitionDone() { - super.onAppTransitionDone(); - mWmService.mWindowsChanged = true; - onTransitionFinished(); - } - void onTransitionFinished() { // If the transition finished callback cannot match the token for some reason, make sure the // rotated state is cleared if it is already invisible. @@ -3256,7 +3247,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } - private boolean allowContentModeSwitch() { + /** + * Note that we only allow displays that are able to show system decorations to use the content + * mode switch; however, not all displays that are able to show system decorations are allowed + * to use the content mode switch. + */ + boolean allowContentModeSwitch() { // The default display should always show system decorations. if (isDefaultDisplay) { return false; @@ -3372,14 +3368,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp void removeImmediately() { mDeferredRemoval = false; try { - // Clear all transitions & screen frozen states when removing display. - mOpeningApps.clear(); - mClosingApps.clear(); - mChangingContainers.clear(); mUnknownAppVisibilityController.clear(); - mAppTransition.removeAppTransitionTimeoutCallbacks(); mTransitionController.unregisterLegacyListener(mFixedRotationTransitionListener); - handleAnimatingStoppedAndTransition(); mDeviceStateController.unregisterDeviceStateCallback(mDeviceStateConsumer); super.removeImmediately(); if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this); @@ -3398,6 +3388,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp .getKeyguardController().onDisplayRemoved(mDisplayId); mWallpaperController.resetLargestDisplay(mDisplay); mWmService.mDisplayWindowSettings.onDisplayRemoved(this); + if (Flags.trackSystemUiContextBeforeWms()) { + getDisplayUiContext().unregisterComponentCallbacks(mSysUiContextConfigCallback); + } } finally { mDisplayReady = false; } @@ -3559,20 +3552,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mDisplayRotation.dumpDebug(proto, DISPLAY_ROTATION); mDisplayFrames.dumpDebug(proto, DISPLAY_FRAMES); proto.write(MIN_SIZE_OF_RESIZEABLE_TASK_DP, mMinSizeOfResizeableTaskDp); - if (mTransitionController.isShellTransitionsEnabled()) { - mTransitionController.dumpDebugLegacy(proto, APP_TRANSITION); - } else { - mAppTransition.dumpDebug(proto, APP_TRANSITION); - } + mTransitionController.dumpDebugLegacy(proto, APP_TRANSITION); if (mFocusedApp != null) { mFocusedApp.writeNameToProto(proto, FOCUSED_APP); } - for (int i = mOpeningApps.size() - 1; i >= 0; i--) { - mOpeningApps.valueAt(i).writeIdentifierToProto(proto, OPENING_APPS); - } - for (int i = mClosingApps.size() - 1; i >= 0; i--) { - mClosingApps.valueAt(i).writeIdentifierToProto(proto, CLOSING_APPS); - } final Task focusedRootTask = getFocusedRootTask(); if (focusedRootTask != null) { @@ -3840,7 +3823,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (mTmpWindow == null) { ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows, display=%d", getDisplayId()); - return null; } return mTmpWindow; } @@ -4831,19 +4813,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } - if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingContainers.isEmpty()) { - pw.println(); - if (mOpeningApps.size() > 0) { - pw.print(" mOpeningApps="); pw.println(mOpeningApps); - } - if (mClosingApps.size() > 0) { - pw.print(" mClosingApps="); pw.println(mClosingApps); - } - if (mChangingContainers.size() > 0) { - pw.print(" mChangingApps="); pw.println(mChangingContainers); - } - } - mUnknownAppVisibilityController.dump(pw, " "); } @@ -5465,7 +5434,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp reconfigureDisplayLocked(); onRequestedOverrideConfigurationChanged(getRequestedOverrideConfiguration()); mWmService.mDisplayNotificationController.dispatchDisplayAdded(this); - // Attach the SystemUiContext to this DisplayContent the get latest configuration. + // Attach the SystemUiContext to this DisplayContent to get latest configuration. // Note that the SystemUiContext will be removed automatically if this DisplayContent // is detached. registerSystemUiContext(); @@ -5473,11 +5442,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } private void registerSystemUiContext() { + final Context systemUiContext = getDisplayUiContext(); final WindowProcessController wpc = mAtmService.getProcessController( - getDisplayUiContext().getIApplicationThread()); + systemUiContext.getIApplicationThread()); mWmService.mWindowContextListenerController.registerWindowContainerListener( - wpc, getDisplayUiContext().getWindowContextToken(), this, + wpc, systemUiContext.getWindowContextToken(), this, INVALID_WINDOW_TYPE, null /* options */); + if (Flags.trackSystemUiContextBeforeWms()) { + systemUiContext.registerComponentCallbacks(mSysUiContextConfigCallback); + } } @Override @@ -5640,60 +5613,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ void requestTransitionAndLegacyPrepare(@WindowManager.TransitionType int transit, @WindowManager.TransitionFlags int flags) { - prepareAppTransition(transit, flags); mTransitionController.requestTransitionIfNeeded(transit, flags, null /* trigger */, this); } void executeAppTransition() { mTransitionController.setReady(this); - if (mAppTransition.isTransitionSet()) { - ProtoLog.w(WM_DEBUG_APP_TRANSITIONS, - "Execute app transition: %s, displayId: %d Callers=%s", - mAppTransition, mDisplayId, Debug.getCallers(5)); - mAppTransition.setReady(); - mWmService.mWindowPlacerLocked.requestTraversal(); - } - } - - /** - * Update pendingLayoutChanges after app transition has finished. - */ - void handleAnimatingStoppedAndTransition() { - int changes = 0; - - mAppTransition.setIdle(); - - for (int i = mNoAnimationNotifyOnTransitionFinished.size() - 1; i >= 0; i--) { - final IBinder token = mNoAnimationNotifyOnTransitionFinished.get(i); - mAppTransition.notifyAppTransitionFinishedLocked(token); - } - mNoAnimationNotifyOnTransitionFinished.clear(); - - mWallpaperController.hideDeferredWallpapersIfNeededLegacy(); - - onAppTransitionDone(); - - changes |= FINISH_LAYOUT_REDO_LAYOUT; - ProtoLog.v(WM_DEBUG_WALLPAPER, "Wallpaper layer changed: assigning layers + relayout"); - computeImeTarget(true /* updateImeTarget */); - mWallpaperMayChange = true; - // Since the window list has been rebuilt, focus might have to be recomputed since the - // actual order of windows might have changed again. - mWmService.mFocusMayChange = true; - - pendingLayoutChanges |= changes; } /** Check if pending app transition is for activity / task launch. */ boolean isNextTransitionForward() { // TODO(b/191375840): decouple "forwardness" from transition system. - if (mTransitionController.isShellTransitionsEnabled()) { - @WindowManager.TransitionType int type = - mTransitionController.getCollectingTransitionType(); - return type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT; - } - return mAppTransition.containsTransitRequest(TRANSIT_OPEN) - || mAppTransition.containsTransitRequest(TRANSIT_TO_FRONT); + final @WindowManager.TransitionType int type = + mTransitionController.getCollectingTransitionType(); + return type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT; } /** @@ -6656,6 +6588,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp forAllTasks((t) -> { t.getRootTask().removeChild(t, "removeAllTasks"); }); } + @NonNull Context getDisplayUiContext() { return mDisplayPolicy.getSystemUiContext(); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 10f591cfd379..7aa2101f516c 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -631,7 +631,6 @@ public class DisplayPolicy { mHandler.post(mAppTransitionFinished); } }; - displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener); displayContent.mTransitionController.registerLegacyListener(mAppTransitionListener); // TODO: Make it can take screenshot on external display @@ -1865,6 +1864,7 @@ public class DisplayPolicy { return mContext; } + @NonNull Context getSystemUiContext() { return mUiContext; } diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java index 539fc123720e..117387553f30 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java +++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java @@ -247,12 +247,7 @@ class DisplayWindowSettings { void setShouldShowSystemDecorsLocked(@NonNull DisplayContent dc, boolean shouldShow) { final boolean changed = (shouldShow != shouldShowSystemDecorsLocked(dc)); - - final DisplayInfo displayInfo = dc.getDisplayInfo(); - final SettingsProvider.SettingsEntry overrideSettings = - mSettingsProvider.getOverrideSettings(displayInfo); - overrideSettings.mShouldShowSystemDecors = shouldShow; - mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings); + setShouldShowSystemDecorsInternalLocked(dc, shouldShow); if (enableDisplayContentModeManagement()) { if (dc.isDefaultDisplay || dc.isPrivate() || !changed) { @@ -269,6 +264,15 @@ class DisplayWindowSettings { } } + void setShouldShowSystemDecorsInternalLocked(@NonNull DisplayContent dc, + boolean shouldShow) { + final DisplayInfo displayInfo = dc.getDisplayInfo(); + final SettingsProvider.SettingsEntry overrideSettings = + mSettingsProvider.getOverrideSettings(displayInfo); + overrideSettings.mShouldShowSystemDecors = shouldShow; + mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings); + } + boolean isHomeSupportedLocked(@NonNull DisplayContent dc) { if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) { // Default display should show home. diff --git a/services/core/java/com/android/server/wm/PresentationController.java b/services/core/java/com/android/server/wm/PresentationController.java index 69463433827f..b3cff9c6cc3d 100644 --- a/services/core/java/com/android/server/wm/PresentationController.java +++ b/services/core/java/com/android/server/wm/PresentationController.java @@ -56,11 +56,6 @@ class PresentationController { ProtoLog.v(WmProtoLogGroups.WM_DEBUG_PRESENTATION, "Presentation added to display %d: %s", win.getDisplayId(), win); mPresentingDisplayIds.add(win.getDisplayId()); - if (enablePresentationForConnectedDisplays()) { - // A presentation hides all activities behind on the same display. - win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, - /*notifyClients=*/ true); - } win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ true); } @@ -76,11 +71,6 @@ class PresentationController { if (displayIdIndex != -1) { mPresentingDisplayIds.remove(displayIdIndex); } - if (enablePresentationForConnectedDisplays()) { - // A presentation hides all activities behind on the same display. - win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, - /*notifyClients=*/ true); - } win.mWmService.mDisplayManagerInternal.onPresentation(displayId, /*isShown=*/ false); } } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index c93efd327096..f309372ab6a2 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2103,10 +2103,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED); } - // Set a transition to ensure that we don't immediately try and update the visibility - // of the activity entering PIP - r.getDisplayContent().prepareAppTransition(TRANSIT_NONE); - transitionController.collect(task); // Defer the windowing mode change until after the transition to prevent the activity @@ -2775,6 +2771,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return; } + if (enableDisplayContentModeManagement() && display.allowContentModeSwitch()) { + mWindowManager.mDisplayWindowSettings + .setShouldShowSystemDecorsInternalLocked(display, + display.mDisplay.canHostTasks()); + } + startSystemDecorations(display, "displayAdded"); // Drop any cached DisplayInfos associated with this display id - the values are now diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index bf9883c76a06..8e5e2f311489 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -54,7 +54,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; -import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; @@ -504,6 +503,17 @@ class Task extends TaskFragment { int mOffsetYForInsets; /** + * When set to true, the task will be kept at a PERCEPTIBLE_APP_ADJ, and downgraded + * to PREVIOUS_APP_ADJ if not in foreground for a period of time. + * One example use case is for desktop form factors, where it is important keep tasks in the + * perceptible state (rather than cached where it may be frozen) when a user moves it to the + * foreground. + * On startup, restored Tasks will not be perceptible, until user actually interacts with it + * (i.e. brings it to the foreground) + */ + boolean mIsPerceptible = false; + + /** * Whether the compatibility overrides that change the resizability of the app should be allowed * for the specific app. */ @@ -1647,8 +1657,7 @@ class Task extends TaskFragment { // Prevent the transition from being executed too early if the top activity is // resumed but the mVisibleRequested of any other activity is true, the transition // should wait until next activity resumed. - if (r.isState(RESUMED) || (r.isVisible() - && !mDisplayContent.mAppTransition.containsTransitRequest(TRANSIT_CLOSE))) { + if (r.isState(RESUMED) || r.isVisible()) { r.finishIfPossible(reason, false /* oomAdj */); } else { r.destroyIfPossible(reason); @@ -2028,7 +2037,7 @@ class Task extends TaskFragment { } if (shouldStartChangeTransition(prevWinMode, mTmpPrevBounds)) { - initializeChangeTransition(mTmpPrevBounds); + mTransitionController.collectVisibleChange(this); } // If the configuration supports persistent bounds (eg. Freeform), keep track of the @@ -2324,11 +2333,6 @@ class Task extends TaskFragment { mLastSurfaceSize.set(width, height); } - @VisibleForTesting - boolean isInChangeTransition() { - return AppTransition.isChangeTransitOld(mTransit); - } - @Override void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); @@ -3854,6 +3858,7 @@ class Task extends TaskFragment { pw.print(ActivityInfo.resizeModeToString(mResizeMode)); pw.print(" mSupportsPictureInPicture="); pw.print(mSupportsPictureInPicture); pw.print(" isResizeable="); pw.println(isResizeable()); + pw.print(" isPerceptible="); pw.println(mIsPerceptible); pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); pw.print(prefix); pw.println(" isTrimmable=" + mIsTrimmableFromRecents); @@ -5293,11 +5298,9 @@ class Task extends TaskFragment { // Place a new activity at top of root task, so it is next to interact with the user. if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) { - mDisplayContent.prepareAppTransition(TRANSIT_NONE); mTaskSupervisor.mNoAnimActivities.add(r); mTransitionController.setNoAnimation(r); } else { - mDisplayContent.prepareAppTransition(TRANSIT_OPEN); mTaskSupervisor.mNoAnimActivities.remove(r); } if (newTask && !r.mLaunchTaskBehind) { @@ -5695,7 +5698,6 @@ class Task extends TaskFragment { ActivityOptions.abort(options); } } - mDisplayContent.prepareAppTransition(transit); } final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options, @@ -5747,12 +5749,9 @@ class Task extends TaskFragment { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr); if (noAnimation) { - mDisplayContent.prepareAppTransition(TRANSIT_NONE); mTaskSupervisor.mNoAnimActivities.add(top); - if (mTransitionController.isShellTransitionsEnabled()) { - mTransitionController.collect(top); - mTransitionController.setNoAnimation(top); - } + mTransitionController.collect(top); + mTransitionController.setNoAnimation(top); ActivityOptions.abort(options); } else { updateTransitLocked(TRANSIT_TO_FRONT, options); @@ -5862,10 +5861,6 @@ class Task extends TaskFragment { moveTaskToBackInner(tr, transition); }); } else { - // Skip the transition for pinned task. - if (!inPinnedWindowingMode()) { - mDisplayContent.prepareAppTransition(TRANSIT_TO_BACK); - } moveTaskToBackInner(tr, null /* transition */); } return true; diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 74059c1cc9b1..9d18d6c4cc89 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -44,10 +44,6 @@ import static android.view.Display.INVALID_DISPLAY; import static android.view.Surface.ROTATION_270; import static android.view.Surface.ROTATION_90; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND; -import static android.view.WindowManager.TRANSIT_NONE; -import static android.view.WindowManager.TRANSIT_OPEN; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_STATES; import static com.android.server.wm.ActivityRecord.State.PAUSED; @@ -56,7 +52,6 @@ import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityRecord.State.STOPPING; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; -import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; @@ -1682,36 +1677,15 @@ class TaskFragment extends WindowContainer<WindowContainer> { final DisplayContent dc = taskDisplayArea.mDisplayContent; if (prev != null) { if (prev.finishing) { - if (DEBUG_TRANSITION) { - Slog.v(TAG_TRANSITION, "Prepare close transition: prev=" + prev); - } if (mTaskSupervisor.mNoAnimActivities.contains(prev)) { anim = false; - dc.prepareAppTransition(TRANSIT_NONE); - } else { - dc.prepareAppTransition(TRANSIT_CLOSE); } prev.setVisibility(false); - } else { - if (DEBUG_TRANSITION) { - Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev); - } - if (mTaskSupervisor.mNoAnimActivities.contains(next)) { - anim = false; - dc.prepareAppTransition(TRANSIT_NONE); - } else { - dc.prepareAppTransition(TRANSIT_OPEN, - next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0); - } - } - } else { - if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous"); - if (mTaskSupervisor.mNoAnimActivities.contains(next)) { + } else if (mTaskSupervisor.mNoAnimActivities.contains(next)) { anim = false; - dc.prepareAppTransition(TRANSIT_NONE); - } else { - dc.prepareAppTransition(TRANSIT_OPEN); } + } else if (mTaskSupervisor.mNoAnimActivities.contains(next)) { + anim = false; } if (anim) { @@ -1910,7 +1884,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { if (!hasDirectChildActivities()) { return false; } - if (mResumedActivity != null && mTransitionController.isTransientLaunch(mResumedActivity)) { + if (mResumedActivity != null && !mResumedActivity.finishing + && mTransitionController.isTransientLaunch(mResumedActivity)) { // Even if the transient activity is occluded, defer pausing (addToStopping will still // be called) it until the transient transition is done. So the current resuming // activity won't need to wait for additional pause complete. @@ -2779,9 +2754,7 @@ class TaskFragment extends WindowContainer<WindowContainer> { } // If this TaskFragment is closing while resizing, crop to the starting bounds instead. - final Rect bounds = isClosingWhenResizing() - ? mDisplayContent.mClosingChangingContainers.get(this) - : getBounds(); + final Rect bounds = getBounds(); final int width = bounds.width(); final int height = bounds.height(); if (!forceUpdate && width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) { diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index e3a5b66b83fd..6c7d979dc43d 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -384,7 +384,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { // an existing task. adjustBoundsToAvoidConflictInDisplayArea(taskDisplayArea, outParams.mBounds); } - } else { + } else if (task == null || !task.hasOverrideBounds()) { if (source != null && source.inFreeformWindowingMode() && resolvedMode == WINDOWING_MODE_FREEFORM && outParams.mBounds.isEmpty() diff --git a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java index 242883612124..e612d8ec0ce6 100644 --- a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java +++ b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java @@ -20,6 +20,7 @@ import static android.graphics.Matrix.MSCALE_X; import static android.graphics.Matrix.MSCALE_Y; import static android.graphics.Matrix.MSKEW_X; import static android.graphics.Matrix.MSKEW_Y; +import static android.view.Display.INVALID_DISPLAY; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TPL; @@ -35,6 +36,7 @@ import android.util.ArrayMap; import android.util.IntArray; import android.util.Pair; import android.util.Size; +import android.util.SparseArray; import android.view.InputWindowHandle; import android.window.ITrustedPresentationListener; import android.window.TrustedPresentationThresholds; @@ -251,7 +253,7 @@ public class TrustedPresentationListenerController { Rect tmpLogicalDisplaySize = new Rect(); Matrix tmpInverseMatrix = new Matrix(); float[] tmpMatrix = new float[9]; - Region coveredRegionsAbove = new Region(); + SparseArray<Region> coveredRegionsAboveByDisplay = new SparseArray<>(); long currTimeMs = System.currentTimeMillis(); ProtoLog.v(WM_DEBUG_TPL, "Checking %d windows", mLastWindowHandles.first.length); @@ -262,7 +264,7 @@ public class TrustedPresentationListenerController { ProtoLog.v(WM_DEBUG_TPL, "Skipping %s", windowHandle.name); continue; } - var displayFound = false; + int displayId = INVALID_DISPLAY; tmpRectF.set(windowHandle.frame); for (var displayHandle : mLastWindowHandles.second) { if (displayHandle.mDisplayId == windowHandle.displayId) { @@ -273,17 +275,18 @@ public class TrustedPresentationListenerController { tmpLogicalDisplaySize.set(0, 0, displayHandle.mLogicalSize.getWidth(), displayHandle.mLogicalSize.getHeight()); tmpRect.intersect(tmpLogicalDisplaySize); - displayFound = true; + displayId = displayHandle.mDisplayId; break; } } - if (!displayFound) { + if (displayId == INVALID_DISPLAY) { ProtoLog.v(WM_DEBUG_TPL, "Skipping %s, no associated display %d", windowHandle.name, windowHandle.displayId); continue; } + Region coveredRegionsAbove = coveredRegionsAboveByDisplay.get(displayId, new Region()); var listeners = mRegisteredListeners.get(windowHandle.getWindowToken()); if (listeners != null) { Region region = new Region(); @@ -304,6 +307,7 @@ public class TrustedPresentationListenerController { } coveredRegionsAbove.op(tmpRect, Region.Op.UNION); + coveredRegionsAboveByDisplay.put(displayId, coveredRegionsAbove); ProtoLog.v(WM_DEBUG_TPL, "coveredRegionsAbove updated with %s frame:%s region:%s", windowHandle.name, tmpRect.toShortString(), coveredRegionsAbove); } diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index c1ef208d1d4d..a8b9fedcdc73 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -292,12 +292,6 @@ class WallpaperController { return false; } - boolean isWallpaperTargetAnimating() { - return mWallpaperTarget != null && mWallpaperTarget.isAnimating(TRANSITION | PARENTS) - && (mWallpaperTarget.mActivityRecord == null - || !mWallpaperTarget.mActivityRecord.isWaitingForTransitionStart()); - } - void hideDeferredWallpapersIfNeededLegacy() { for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { final WallpaperWindowToken token = mWallpaperTokens.get(i); @@ -837,14 +831,6 @@ class WallpaperController { // Use the old target if new target is hidden but old target // is not. If they're both hidden, still use the new target. mWallpaperTarget = prevWallpaperTarget; - } else if (newTargetHidden == oldTargetHidden - && !mDisplayContent.mOpeningApps.contains(wallpaperTarget.mActivityRecord) - && (mDisplayContent.mOpeningApps.contains(prevWallpaperTarget.mActivityRecord) - || mDisplayContent.mClosingApps.contains(prevWallpaperTarget.mActivityRecord))) { - // If they're both hidden (or both not hidden), prefer the one that's currently in - // opening or closing app list, this allows transition selection logic to better - // determine the wallpaper status of opening/closing apps. - mWallpaperTarget = prevWallpaperTarget; } result.setWallpaperTarget(wallpaperTarget); diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 7c88abcec7ec..9506ffeb2792 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -217,8 +217,7 @@ class WallpaperWindowToken extends WindowToken { } // If in a transition, defer commits for activities that are going invisible - if (!visible && (mTransitionController.inTransition() - || getDisplayContent().mAppTransition.isRunning())) { + if (!visible && mTransitionController.inTransition()) { return; } diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 95cdf46ea488..d0d2067ac4bc 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -16,9 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; @@ -29,25 +26,15 @@ import static android.content.pm.ActivityInfo.reverseOrientation; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; -import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.UserHandle.USER_NULL; import static android.view.SurfaceControl.Transaction; import static android.view.WindowInsets.Type.InsetsType; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; -import static android.view.WindowManager.TRANSIT_CHANGE; -import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR; import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM; -import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS; -import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ORIENTATION; import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_SYNC_ENGINE; -import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION; -import static com.android.server.wm.AppTransition.isActivityTransitOld; -import static com.android.server.wm.AppTransition.isTaskFragmentTransitOld; -import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; @@ -66,7 +53,6 @@ import static com.android.server.wm.WindowContainerProto.VISIBLE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; -import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM; import android.annotation.CallSuper; import android.annotation.ColorInt; @@ -82,10 +68,8 @@ import android.graphics.Rect; import android.os.Debug; import android.os.IBinder; import android.os.RemoteException; -import android.os.Trace; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.Pair; import android.util.Pools; import android.util.RotationUtils; import android.util.Slog; @@ -103,14 +87,11 @@ import android.view.SurfaceControl.Builder; import android.view.SurfaceControlViewHost; import android.view.WindowManager; import android.view.WindowManager.TransitionOldType; -import android.view.animation.Animation; import android.window.IWindowContainerToken; import android.window.WindowContainerToken; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.graphics.ColorUtils; import com.android.internal.protolog.ProtoLog; -import com.android.internal.protolog.common.LogLevel; import com.android.internal.util.ToBooleanFunction; import com.android.server.wm.SurfaceAnimator.Animatable; import com.android.server.wm.SurfaceAnimator.AnimationType; @@ -901,10 +882,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< */ @CallSuper void removeImmediately() { - final DisplayContent dc = getDisplayContent(); - if (dc != null) { - dc.mClosingChangingContainers.remove(this); - } while (!mChildren.isEmpty()) { final E child = mChildren.getLast(); child.removeImmediately(); @@ -1116,10 +1093,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (asWindowState() == null) { mTransitionController.collect(this); } - // Cancel any change transition queued-up for this container on the old display when - // this container is moved from the old display. - mDisplayContent.mClosingChangingContainers.remove(this); - mDisplayContent.mChangingContainers.remove(this); } mDisplayContent = dc; if (dc != null && dc != this && mPendingTransaction != null) { @@ -1268,14 +1241,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } /** - * @return {@code true} when the container is waiting the app transition start, {@code false} - * otherwise. - */ - boolean isWaitingForTransitionStart() { - return false; - } - - /** * @return {@code true} if in this subtree of the hierarchy we have an * {@code ActivityRecord#isAnimating(TRANSITION)}, {@code false} otherwise. */ @@ -1302,13 +1267,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return isAnimating(0 /* self only */); } - /** - * @return {@code true} if the container is in changing app transition. - */ - boolean isChangingAppTransition() { - return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this); - } - boolean inTransition() { return mTransitionController.inTransition(this); } @@ -1339,31 +1297,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } /** - * Returns true if the container or one of its children as some content it can display or wants - * to display (e.g. app views or saved surface). - * - * NOTE: While this method will return true if the there is some content to display, it doesn't - * mean the container is visible. Use {@link #isVisible()} to determine if the container is - * visible. - */ - boolean hasContentToDisplay() { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final WindowContainer wc = mChildren.get(i); - if (wc.hasContentToDisplay()) { - return true; - } - } - return false; - } - - /** * Returns true if the container or one of its children is considered visible from the * WindowManager perspective which usually means valid surface and some other internal state * are true. * * NOTE: While this method will return true if the surface is visible, it doesn't mean the - * client has actually displayed any content. Use {@link #hasContentToDisplay()} to determine if - * the container has any content to display. + * client has actually displayed any content. */ boolean isVisible() { // TODO: Will this be more correct if it checks the visibility of its parents? @@ -1427,12 +1366,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return setVisibleRequested(newVisReq); } - /** Whether this window is closing while resizing. */ - boolean isClosingWhenResizing() { - return mDisplayContent != null - && mDisplayContent.mClosingChangingContainers.containsKey(this); - } - void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(HASH_CODE, System.identityHashCode(this)); @@ -1510,13 +1443,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } } - void onAppTransitionDone() { - for (int i = mChildren.size() - 1; i >= 0; --i) { - final WindowContainer wc = mChildren.get(i); - wc.onAppTransitionDone(); - } - } - /** * Called when this container or one of its descendants changed its requested orientation, and * wants this container to handle it or pass it to its parent. @@ -3044,36 +2970,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< || (getParent() != null && getParent().inPinnedWindowingMode()); } - /** - * Initializes a change transition. - * - * For now, this will only be called for the following cases: - * 1. {@link Task} is changing windowing mode between fullscreen and freeform. - * 2. {@link TaskFragment} is organized and is changing window bounds. - * 3. {@link ActivityRecord} is reparented into an organized {@link TaskFragment}. (The - * transition will happen on the {@link TaskFragment} for this case). - * - * This shouldn't be called on other {@link WindowContainer} unless there is a valid - * use case. - * - * @param startBounds The original bounds (on screen) of the surface we are snapshotting. - */ - void initializeChangeTransition(Rect startBounds, @Nullable SurfaceControl freezeTarget) { - if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) { - mDisplayContent.mTransitionController.collectVisibleChange(this); - return; - } - mDisplayContent.prepareAppTransition(TRANSIT_CHANGE); - mDisplayContent.mChangingContainers.add(this); - // Calculate the relative position in parent container. - final Rect parentBounds = getParent().getBounds(); - mTmpPoint.set(startBounds.left - parentBounds.left, startBounds.top - parentBounds.top); - } - - void initializeChangeTransition(Rect startBounds) { - initializeChangeTransition(startBounds, null /* freezeTarget */); - } - ArraySet<WindowContainer> getAnimationSources() { return mSurfaceAnimationSources; } @@ -3099,265 +2995,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< getRelativePosition(outPosition); } - /** - * Applies the app transition animation according the given the layout properties in the - * window hierarchy. - * - * @param lp The layout parameters of the window. - * @param transit The app transition type indicates what kind of transition to be applied. - * @param enter Whether the app transition is entering transition or not. - * @param isVoiceInteraction Whether the container is participating in voice interaction or not. - * @param sources {@link ActivityRecord}s which causes this app transition animation. - * - * @return {@code true} when the container applied the app transition, {@code false} if the - * app transition is disabled or skipped. - * - * @see #getAnimationAdapter - */ - boolean applyAnimation(WindowManager.LayoutParams lp, @TransitionOldType int transit, - boolean enter, boolean isVoiceInteraction, - @Nullable ArrayList<WindowContainer> sources) { - if (mWmService.mDisableTransitionAnimation) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, - "applyAnimation: transition animation is disabled or skipped. " - + "container=%s", this); - cancelAnimation(); - return false; - } - - // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason - // to animate and it can cause strange artifacts when we unfreeze the display if some - // different animation is running. - try { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation"); - if (okToAnimate()) { - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, - "applyAnimation: transit=%s, enter=%b, wc=%s", - AppTransition.appTransitionOldToString(transit), enter, this); - applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources); - } else { - cancelAnimation(); - } - } finally { - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - } - - return isAnimating(); - } - - /** - * Gets the {@link AnimationAdapter} according the given window layout properties in the window - * hierarchy. - * - * @return The return value will always contain two elements, one for normal animations and the - * other for thumbnail animation, both can be {@code null}. - * - * @See com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord - * @See LocalAnimationAdapter - */ - Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp, - @TransitionOldType int transit, boolean enter, boolean isVoiceInteraction) { - final Pair<AnimationAdapter, AnimationAdapter> resultAdapters; - final int appRootTaskClipMode = getDisplayContent().mAppTransition.getAppRootTaskClipMode(); - - // Separate position and size for use in animators. - final Rect screenBounds = getAnimationBounds(appRootTaskClipMode); - mTmpRect.set(screenBounds); - getAnimationPosition(mTmpPoint); - mTmpRect.offsetTo(0, 0); - - final boolean isChanging = AppTransition.isChangeTransitOld(transit) && enter - && isChangingAppTransition(); - - if (isChanging) { - final float durationScale = mWmService.getTransitionAnimationScaleLocked(); - final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo(); - mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y); - - final AnimationAdapter adapter = new LocalAnimationAdapter( - new WindowChangeAnimationSpec(null /* startBounds */, mTmpRect, - displayInfo, durationScale, true /* isAppAnimation */, - false /* isThumbnail */), - getSurfaceAnimationRunner()); - - final AnimationAdapter thumbnailAdapter = null; - resultAdapters = new Pair<>(adapter, thumbnailAdapter); - mTransit = transit; - mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags(); - } else { - mNeedsAnimationBoundsLayer = (appRootTaskClipMode == ROOT_TASK_CLIP_AFTER_ANIM); - final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction); - - if (a != null) { - // Only apply corner radius to animation if we're not in multi window mode. - // We don't want rounded corners when in pip or split screen. - final float windowCornerRadius = !inMultiWindowMode() - ? getDisplayContent().getWindowCornerRadius() - : 0; - if (asActivityRecord() != null - && asActivityRecord().isNeedsLetterboxedAnimation()) { - asActivityRecord().getLetterboxInnerBounds(mTmpRect); - } - AnimationAdapter adapter = new LocalAnimationAdapter( - new WindowAnimationSpec(a, mTmpPoint, mTmpRect, - getDisplayContent().mAppTransition.canSkipFirstFrame(), - appRootTaskClipMode, true /* isAppAnimation */, windowCornerRadius), - getSurfaceAnimationRunner()); - - resultAdapters = new Pair<>(adapter, null); - mNeedsZBoost = a.getZAdjustment() == Animation.ZORDER_TOP - || AppTransition.isClosingTransitOld(transit); - mTransit = transit; - mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags(); - } else { - resultAdapters = new Pair<>(null, null); - } - } - return resultAdapters; - } - - protected void applyAnimationUnchecked(WindowManager.LayoutParams lp, boolean enter, - @TransitionOldType int transit, boolean isVoiceInteraction, - @Nullable ArrayList<WindowContainer> sources) { - final Task task = asTask(); - if (task != null && !enter && !task.isActivityTypeHomeOrRecents()) { - final InsetsControlTarget imeTarget = mDisplayContent.getImeTarget(IME_TARGET_LAYERING); - final boolean isImeLayeringTarget = imeTarget != null && imeTarget.getWindow() != null - && imeTarget.getWindow().getTask() == task; - // Attach and show the IME screenshot when the task is the IME target and performing - // task closing transition to the next task. - if (isImeLayeringTarget && AppTransition.isTaskCloseTransitOld(transit)) { - mDisplayContent.showImeScreenshot(); - } - } - final Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp, - transit, enter, isVoiceInteraction); - AnimationAdapter adapter = adapters.first; - AnimationAdapter thumbnailAdapter = adapters.second; - if (adapter != null) { - if (sources != null) { - mSurfaceAnimationSources.addAll(sources); - } - - AnimationRunnerBuilder animationRunnerBuilder = new AnimationRunnerBuilder(); - - // Check if the animation requests to show background color for Activity and embedded - // TaskFragment. - final ActivityRecord activityRecord = asActivityRecord(); - final TaskFragment taskFragment = asTaskFragment(); - if (adapter.getShowBackground() - // Check if it is Activity transition. - && ((activityRecord != null && isActivityTransitOld(transit)) - // Check if it is embedded TaskFragment transition. - || (taskFragment != null && taskFragment.isEmbedded() - && isTaskFragmentTransitOld(transit)))) { - final @ColorInt int backgroundColorForTransition; - if (adapter.getBackgroundColor() != 0) { - // If available use the background color provided through getBackgroundColor - // which if set originates from a call to overridePendingAppTransition. - backgroundColorForTransition = adapter.getBackgroundColor(); - } else { - final TaskFragment organizedTf = activityRecord != null - ? activityRecord.getOrganizedTaskFragment() - : taskFragment.getOrganizedTaskFragment(); - if (organizedTf != null && organizedTf.getAnimationParams() - .getAnimationBackgroundColor() != DEFAULT_ANIMATION_BACKGROUND_COLOR) { - // This window is embedded and has an animation background color set on the - // TaskFragment. Pass this color with this window, so the handler can use it - // as the animation background color if needed, - backgroundColorForTransition = organizedTf.getAnimationParams() - .getAnimationBackgroundColor(); - } else { - // Otherwise default to the window's background color if provided through - // the theme as the background color for the animation - the top most window - // with a valid background color and showBackground set takes precedence. - final Task parentTask = activityRecord != null - ? activityRecord.getTask() - : taskFragment.getTask(); - backgroundColorForTransition = parentTask.getTaskDescription() - .getBackgroundColor(); - } - } - // Set to opaque for animation background to prevent it from exposing the blank - // background or content below. - animationRunnerBuilder.setTaskBackgroundColor(ColorUtils.setAlphaComponent( - backgroundColorForTransition, 255)); - } - - animationRunnerBuilder.build() - .startAnimation(getPendingTransaction(), adapter, !isVisible(), - ANIMATION_TYPE_APP_TRANSITION, thumbnailAdapter); - - if (adapter.getShowWallpaper()) { - getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; - } - } - } - final SurfaceAnimationRunner getSurfaceAnimationRunner() { return mWmService.mSurfaceAnimationRunner; } - private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, - boolean isVoiceInteraction) { - if ((isOrganized() - // TODO(b/161711458): Clean-up when moved to shell. - && getWindowingMode() != WINDOWING_MODE_FULLSCREEN - && getWindowingMode() != WINDOWING_MODE_FREEFORM - && getWindowingMode() != WINDOWING_MODE_MULTI_WINDOW)) { - return null; - } - - final DisplayContent displayContent = getDisplayContent(); - final DisplayInfo displayInfo = displayContent.getDisplayInfo(); - final int width = displayInfo.appWidth; - final int height = displayInfo.appHeight; - ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: container=%s", this); - - // Determine the visible rect to calculate the thumbnail clip with - // getAnimationFrames. - final Rect frame = new Rect(0, 0, width, height); - final Rect displayFrame = new Rect(0, 0, - displayInfo.logicalWidth, displayInfo.logicalHeight); - final Rect insets = new Rect(); - final Rect stableInsets = new Rect(); - final Rect surfaceInsets = new Rect(); - getAnimationFrames(frame, insets, stableInsets, surfaceInsets); - - if (mLaunchTaskBehind) { - // Differentiate the two animations. This one which is briefly on the screen - // gets the !enter animation, and the other one which remains on the - // screen gets the enter animation. Both appear in the mOpeningApps set. - enter = false; - } - ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, - "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s " - + "surfaceInsets=%s", - AppTransition.appTransitionOldToString(transit), enter, frame, insets, - surfaceInsets); - final Configuration displayConfig = displayContent.getConfiguration(); - final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter, - displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets, - surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this); - if (a != null) { - if (a != null) { - // Setup the maximum app transition duration to prevent malicious app may set a long - // animation duration or infinite repeat counts for the app transition through - // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition. - a.restrictDuration(MAX_APP_TRANSITION_DURATION); - } - if (ProtoLog.isEnabled(WM_DEBUG_ANIM, LogLevel.DEBUG)) { - ProtoLog.i(WM_DEBUG_ANIM, "Loaded animation %s for %s, duration: %d, stack=%s", - a, this, ((a != null) ? a.getDuration() : 0), Debug.getCallers(20)); - } - final int containingWidth = frame.width(); - final int containingHeight = frame.height(); - a.initialize(containingWidth, containingHeight, width, height); - a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked()); - } - return a; - } - boolean canCreateRemoteAnimationTarget() { return false; } @@ -3519,9 +3160,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< && (mSurfaceAnimator.getAnimationType() & typesToCheck) > 0) { return true; } - if ((flags & TRANSITION) != 0 && isWaitingForTransitionStart()) { - return true; - } return false; } @@ -3603,13 +3241,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return; } - if (isClosingWhenResizing()) { - // This container is closing while resizing, keep its surface at the starting position - // to prevent animation flicker. - getRelativePosition(mDisplayContent.mClosingChangingContainers.get(this), mTmpPos); - } else { - getRelativePosition(mTmpPos); - } + getRelativePosition(mTmpPos); final int deltaRotation = getRelativeDisplayRotation(); if (mTmpPos.equals(mLastSurfacePosition) && deltaRotation == mLastDeltaRotation) { return; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d699a689459e..8aed91b2dc66 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -157,6 +157,7 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY; import static com.android.server.wm.WindowManagerServiceDumpProto.ROOT_WINDOW_CONTAINER; import static com.android.server.wm.WindowManagerServiceDumpProto.WINDOW_FRAMES_VALID; import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions; +import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays; import static com.android.window.flags.Flags.multiCrop; import static com.android.window.flags.Flags.setScPropertiesInClient; @@ -1820,125 +1821,158 @@ public class WindowManagerService extends IWindowManager.Stub final boolean hideSystemAlertWindows = shouldHideNonSystemOverlayWindow(win); win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows); - boolean imMayMove = true; - - win.mToken.addWindow(win); - displayPolicy.addWindowLw(win, attrs); - displayPolicy.setDropInputModePolicy(win, win.mAttrs); - if (type == TYPE_APPLICATION_STARTING && activity != null) { - activity.attachStartingWindow(win); - ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s", - activity, win); - } else if (type == TYPE_INPUT_METHOD - // IME window is always touchable. - // Ignore non-touchable windows e.g. Stylus InkWindow.java. - && (win.getAttrs().flags & FLAG_NOT_TOUCHABLE) == 0) { - displayContent.setInputMethodWindowLocked(win); - imMayMove = false; - } else if (type == TYPE_INPUT_METHOD_DIALOG) { - displayContent.computeImeTarget(true /* updateImeTarget */); - imMayMove = false; - } else { - if (type == TYPE_WALLPAPER) { - displayContent.mWallpaperController.clearLastWallpaperTimeoutTime(); - displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; - } else if (win.hasWallpaper()) { - displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; - } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) { - // If there is currently a wallpaper being shown, and - // the base layer of the new window is below the current - // layer of the target window, then adjust the wallpaper. - // This is to avoid a new window being placed between the - // wallpaper and its target. - displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; + // Only a presentation window needs a transition because its visibility affets the + // lifecycle of apps below (b/390481865). + if (enablePresentationForConnectedDisplays() && win.isPresentation()) { + Transition transition = null; + if (!win.mTransitionController.isCollecting()) { + transition = win.mTransitionController.createAndStartCollecting(TRANSIT_OPEN); + } + win.mTransitionController.collect(win.mToken); + res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState, + outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs); + // A presentation hides all activities behind on the same display. + win.mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, + /*notifyClients=*/ true); + win.mTransitionController.getCollectingTransition().setReady(win.mToken, true); + if (transition != null) { + win.mTransitionController.requestStartTransition(transition, null, + null /* remoteTransition */, null /* displayChange */); } + } else { + res |= addWindowInner(win, displayPolicy, activity, displayContent, outInsetsState, + outAttachedFrame, outActiveControls, client, outSizeCompatScale, attrs); } + } - final WindowStateAnimator winAnimator = win.mWinAnimator; - winAnimator.mEnterAnimationPending = true; - winAnimator.mEnteringAnimation = true; + Binder.restoreCallingIdentity(origId); - if (displayPolicy.areSystemBarsForcedConsumedLw()) { - res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS; - } - if (displayContent.isInTouchMode()) { - res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; - } - if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) { - res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; + return res; + } + + private int addWindowInner(@NonNull WindowState win, @NonNull DisplayPolicy displayPolicy, + @NonNull ActivityRecord activity, @NonNull DisplayContent displayContent, + @NonNull InsetsState outInsetsState, @NonNull Rect outAttachedFrame, + @NonNull InsetsSourceControl.Array outActiveControls, @NonNull IWindow client, + @NonNull float[] outSizeCompatScale, @NonNull LayoutParams attrs) { + int res = 0; + final int type = attrs.type; + boolean imMayMove = true; + + win.mToken.addWindow(win); + displayPolicy.addWindowLw(win, attrs); + displayPolicy.setDropInputModePolicy(win, win.mAttrs); + if (type == TYPE_APPLICATION_STARTING && activity != null) { + activity.attachStartingWindow(win); + ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s", + activity, win); + } else if (type == TYPE_INPUT_METHOD + // IME window is always touchable. + // Ignore non-touchable windows e.g. Stylus InkWindow.java. + && (win.getAttrs().flags & FLAG_NOT_TOUCHABLE) == 0) { + displayContent.setInputMethodWindowLocked(win); + imMayMove = false; + } else if (type == TYPE_INPUT_METHOD_DIALOG) { + displayContent.computeImeTarget(true /* updateImeTarget */); + imMayMove = false; + } else { + if (type == TYPE_WALLPAPER) { + displayContent.mWallpaperController.clearLastWallpaperTimeoutTime(); + displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; + } else if (win.hasWallpaper()) { + displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; + } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) { + // If there is currently a wallpaper being shown, and + // the base layer of the new window is below the current + // layer of the target window, then adjust the wallpaper. + // This is to avoid a new window being placed between the + // wallpaper and its target. + displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; } + } - displayContent.getInputMonitor().setUpdateInputWindowsNeededLw(); + final WindowStateAnimator winAnimator = win.mWinAnimator; + winAnimator.mEnterAnimationPending = true; + winAnimator.mEnteringAnimation = true; - boolean focusChanged = false; - if (win.canReceiveKeys()) { - focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, - false /*updateInputWindows*/); - if (focusChanged) { - imMayMove = false; - } - } + if (displayPolicy.areSystemBarsForcedConsumedLw()) { + res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS; + } + if (displayContent.isInTouchMode()) { + res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; + } + if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) { + res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; + } - if (imMayMove) { - displayContent.computeImeTarget(true /* updateImeTarget */); - if (win.isImeOverlayLayeringTarget()) { - dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type, - win.isVisibleRequestedOrAdding(), false /* removed */, - displayContent.getDisplayId()); - } - } + displayContent.getInputMonitor().setUpdateInputWindowsNeededLw(); - // Don't do layout here, the window must call - // relayout to be displayed, so we'll do it there. - if (win.mActivityRecord != null && win.mActivityRecord.isEmbedded()) { - // Assign child layers from the parent Task if the Activity is embedded. - win.getTask().assignChildLayers(); - } else { - win.getParent().assignChildLayers(); + boolean focusChanged = false; + if (win.canReceiveKeys()) { + focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, + false /*updateInputWindows*/); + if (focusChanged) { + imMayMove = false; } + } - if (focusChanged) { - displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus, - false /*updateInputWindows*/); + if (imMayMove) { + displayContent.computeImeTarget(true /* updateImeTarget */); + if (win.isImeOverlayLayeringTarget()) { + dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type, + win.isVisibleRequestedOrAdding(), false /* removed */, + displayContent.getDisplayId()); } - displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/); + } - ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s" - + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5)); + // Don't do layout here, the window must call + // relayout to be displayed, so we'll do it there. + if (win.mActivityRecord != null && win.mActivityRecord.isEmbedded()) { + // Assign child layers from the parent Task if the Activity is embedded. + win.getTask().assignChildLayers(); + } else { + win.getParent().assignChildLayers(); + } - boolean needToSendNewConfiguration = - win.isVisibleRequestedOrAdding() && displayContent.updateOrientation(); - if (win.providesDisplayDecorInsets()) { - needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo(); - } - if (needToSendNewConfiguration) { - displayContent.sendNewConfiguration(); - } + if (focusChanged) { + displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus, + false /*updateInputWindows*/); + } + displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/); - // This window doesn't have a frame yet. Don't let this window cause the insets change. - displayContent.getInsetsStateController().updateAboveInsetsState( - false /* notifyInsetsChanged */); + ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s" + + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5)); - win.fillInsetsState(outInsetsState, true /* copySources */); - getInsetsSourceControls(win, outActiveControls); + boolean needToSendNewConfiguration = + win.isVisibleRequestedOrAdding() && displayContent.updateOrientation(); + if (win.providesDisplayDecorInsets()) { + needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo(); + } + if (needToSendNewConfiguration) { + displayContent.sendNewConfiguration(); + } - if (win.mLayoutAttached) { - outAttachedFrame.set(win.getParentWindow().getFrame()); - if (win.mInvGlobalScale != 1f) { - outAttachedFrame.scale(win.mInvGlobalScale); - } - } else { - // Make this invalid which indicates a null attached frame. - outAttachedFrame.set(0, 0, -1, -1); - } - outSizeCompatScale[0] = win.getCompatScaleForClient(); + // This window doesn't have a frame yet. Don't let this window cause the insets change. + displayContent.getInsetsStateController().updateAboveInsetsState( + false /* notifyInsetsChanged */); + + win.fillInsetsState(outInsetsState, true /* copySources */); + getInsetsSourceControls(win, outActiveControls); - if (res >= ADD_OKAY && win.isPresentation()) { - mPresentationController.onPresentationAdded(win); + if (win.mLayoutAttached) { + outAttachedFrame.set(win.getParentWindow().getFrame()); + if (win.mInvGlobalScale != 1f) { + outAttachedFrame.scale(win.mInvGlobalScale); } + } else { + // Make this invalid which indicates a null attached frame. + outAttachedFrame.set(0, 0, -1, -1); } + outSizeCompatScale[0] = win.getCompatScaleForClient(); - Binder.restoreCallingIdentity(origId); + if (res >= ADD_OKAY && win.isPresentation()) { + mPresentationController.onPresentationAdded(win); + } return res; } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 4c53ba53a506..4b4736ec6c59 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1060,7 +1060,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub effects |= applyChanges(taskFragment, c); if (taskFragment.shouldStartChangeTransition(mTmpBounds0, mTmpBounds1)) { - taskFragment.initializeChangeTransition(mTmpBounds0); + mTransitionController.collectVisibleChange(taskFragment); } taskFragment.continueOrganizedTaskFragmentSurfaceUpdate(); return effects; diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 30dde543b9d4..b2d28a369edc 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -37,6 +37,7 @@ import static com.android.server.wm.ActivityRecord.State.PAUSING; import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityRecord.State.STARTED; import static com.android.server.wm.ActivityRecord.State.STOPPING; +import static com.android.server.wm.ActivityRecord.State.STOPPED; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE; @@ -344,6 +345,12 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio */ private volatile int mActivityStateFlags = ACTIVITY_STATE_FLAG_MASK_MIN_TASK_LAYER; + /** + * The most recent timestamp of when one of this process's stopped activities in a + * perceptible task became stopped. Written by window manager and read by activity manager. + */ + private volatile long mPerceptibleTaskStoppedTimeMillis = Long.MIN_VALUE; + public WindowProcessController(@NonNull ActivityTaskManagerService atm, @NonNull ApplicationInfo info, String name, int uid, int userId, Object owner, @NonNull WindowProcessListener listener) { @@ -1228,6 +1235,17 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio return mActivityStateFlags; } + /** + * Returns the most recent timestamp when one of this process's stopped activities in a + * perceptible task became stopped. It should only be called if {@link #hasActivities} + * returns {@code true} and {@link #getActivityStateFlags} does not have any of + * the ACTIVITY_STATE_FLAG_IS_(VISIBLE|PAUSING_OR_PAUSED|STOPPING) bit set. + */ + @HotPath(caller = HotPath.OOM_ADJUSTMENT) + public long getPerceptibleTaskStoppedTimeMillis() { + return mPerceptibleTaskStoppedTimeMillis; + } + void computeProcessActivityState() { // Since there could be more than one activities in a process record, we don't need to // compute the OomAdj with each of them, just need to find out the activity with the @@ -1239,6 +1257,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio int minTaskLayer = Integer.MAX_VALUE; int stateFlags = 0; int nonOccludedRatio = 0; + long perceptibleTaskStoppedTimeMillis = Long.MIN_VALUE; final boolean wasResumed = hasResumedActivity(); final boolean wasAnyVisible = (mActivityStateFlags & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0; @@ -1287,6 +1306,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio bestInvisibleState = STOPPING; // Not "finishing" if any of activity isn't finishing. allStoppingFinishing &= r.finishing; + } else if (bestInvisibleState == DESTROYED && r.isState(STOPPED)) { + if (task.mIsPerceptible) { + perceptibleTaskStoppedTimeMillis = + Long.max(r.mStoppedTime, perceptibleTaskStoppedTimeMillis); + } } } } @@ -1324,6 +1348,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } mActivityStateFlags = stateFlags; + mPerceptibleTaskStoppedTimeMillis = perceptibleTaskStoppedTimeMillis; final boolean anyVisible = (stateFlags & (ACTIVITY_STATE_FLAG_IS_VISIBLE | ACTIVITY_STATE_FLAG_IS_WINDOW_VISIBLE)) != 0; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 589724182980..bfedc90497ae 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -95,6 +95,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; +import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER; import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET; @@ -182,6 +183,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.enablePresentationForConnectedDisplays; import static com.android.window.flags.Flags.surfaceTrustedOverlay; import android.annotation.CallSuper; @@ -1696,17 +1698,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP || mActivityRecord.isStartingWindowDisplayed()); } - @Override - boolean hasContentToDisplay() { - if (!isDrawn() && (mViewVisibility == View.VISIBLE - || (isAnimating(TRANSITION | PARENTS) - && !getDisplayContent().mAppTransition.isTransitionSet()))) { - return true; - } - - return super.hasContentToDisplay(); - } - private boolean isVisibleByPolicyOrInsets() { return isVisibleByPolicy() // If we don't have a provider, this window isn't used as a window generating @@ -2297,11 +2288,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP dc.updateImeInputAndControlTarget(null); } - final int type = mAttrs.type; - - if (isPresentation()) { - mWmService.mPresentationController.onPresentationRemoved(this); - } // Check if window provides non decor insets before clearing its provided insets. final boolean windowProvidesDisplayDecorInsets = providesDisplayDecorInsets(); @@ -2442,11 +2428,33 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } - removeImmediately(); - mWmService.updateFocusedWindowLocked(isFocused() - ? UPDATE_FOCUS_REMOVING_FOCUS - : UPDATE_FOCUS_NORMAL, - true /*updateInputWindows*/); + // Only a presentation window needs a transition because its visibility affets the + // lifecycle of apps below (b/390481865). + if (enablePresentationForConnectedDisplays() && isPresentation()) { + Transition transition = null; + if (!mTransitionController.isCollecting()) { + transition = mTransitionController.createAndStartCollecting(TRANSIT_CLOSE); + } + mTransitionController.collect(mToken); + mAnimatingExit = true; + mRemoveOnExit = true; + mToken.setVisibleRequested(false); + mWmService.mPresentationController.onPresentationRemoved(this); + // A presentation hides all activities behind on the same display. + mDisplayContent.ensureActivitiesVisible(/*starting=*/ null, + /*notifyClients=*/ true); + mTransitionController.getCollectingTransition().setReady(mToken, true); + if (transition != null) { + mTransitionController.requestStartTransition(transition, null, + null /* remoteTransition */, null /* displayChange */); + } + } else { + removeImmediately(); + mWmService.updateFocusedWindowLocked(isFocused() + ? UPDATE_FOCUS_REMOVING_FOCUS + : UPDATE_FOCUS_NORMAL, + true /*updateInputWindows*/); + } } finally { Binder.restoreCallingIdentity(origId); } @@ -3272,13 +3280,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mDestroying = false; destroyedSomething = true; } - - // Since mDestroying will affect ActivityRecord#allDrawn, we need to perform another - // traversal in case we are waiting on this window to start the transition. - if (getDisplayContent().mAppTransition.isTransitionSet() - && getDisplayContent().mOpeningApps.contains(mActivityRecord)) { - mWmService.mWindowPlacerLocked.requestTraversal(); - } } return destroyedSomething; diff --git a/services/core/java/com/android/server/wm/utils/WindowStyleCache.java b/services/core/java/com/android/server/wm/utils/WindowStyleCache.java new file mode 100644 index 000000000000..a253c2c75aa2 --- /dev/null +++ b/services/core/java/com/android/server/wm/utils/WindowStyleCache.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.utils; + +import android.content.res.TypedArray; +import android.util.ArrayMap; +import android.util.SparseArray; + +import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.policy.AttributeCache; + +import java.util.function.Function; + +/** + * A wrapper of AttributeCache to preserve more dedicated style caches. + * @param <T> The type of style cache. + */ +public class WindowStyleCache<T> { + @GuardedBy("itself") + private final ArrayMap<String, SparseArray<T>> mCache = new ArrayMap<>(); + private final Function<TypedArray, T> mEntryFactory; + + public WindowStyleCache(Function<TypedArray, T> entryFactory) { + mEntryFactory = entryFactory; + } + + /** Returns the cached entry. */ + public T get(String packageName, int theme, int userId) { + SparseArray<T> themeMap; + synchronized (mCache) { + themeMap = mCache.get(packageName); + if (themeMap != null) { + T style = themeMap.get(theme); + if (style != null) { + return style; + } + } + } + + final AttributeCache attributeCache = AttributeCache.instance(); + if (attributeCache == null) { + return null; + } + final AttributeCache.Entry ent = attributeCache.get(packageName, theme, + R.styleable.Window, userId); + if (ent == null) { + return null; + } + + final T style = mEntryFactory.apply(ent.array); + synchronized (mCache) { + if (themeMap == null) { + mCache.put(packageName, themeMap = new SparseArray<>()); + } + themeMap.put(theme, style); + } + return style; + } + + /** Called when the package is updated or removed. */ + public void invalidatePackage(String packageName) { + synchronized (mCache) { + mCache.remove(packageName); + } + } +} diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 0d0c0bad24fa..a8c49e11e4e9 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -47,6 +47,7 @@ #include <dispatcher/Entry.h> #include <include/gestures.h> #include <input/Input.h> +#include <input/InputFlags.h> #include <input/PointerController.h> #include <input/PrintTools.h> #include <input/SpriteController.h> @@ -666,7 +667,7 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO } void NativeInputManager::setDisplayTopology(JNIEnv* env, jobject topologyGraph) { - if (!com::android::input::flags::connected_displays_cursor()) { + if (!InputFlags::connectedDisplaysCursorEnabled()) { return; } diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java index 40554ac51b24..7edf646a48f6 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java @@ -21,11 +21,16 @@ import static com.android.server.credentials.CredentialManagerService.getPrimary import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.credentials.CredentialManager; import android.credentials.CredentialProviderInfo; +import android.credentials.flags.Flags; import android.service.credentials.CredentialProviderInfoFactory; +import android.service.credentials.CredentialProviderService; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -78,14 +83,16 @@ public final class CredentialManagerServiceImpl extends mInfo = providerInfo; } - @Override // from PerUserSystemService when a new setting based service is to be created + @Override // from PerUserSystemService when a new service is to be created @GuardedBy("mLock") protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent) - throws PackageManager.NameNotFoundException { + throws PackageManager.NameNotFoundException, SecurityException, NullPointerException { + boolean isSystemProvider = false; if (mInfo != null) { Slog.i(TAG, "newServiceInfoLocked, mInfo not null : " + mInfo.getServiceInfo().getComponentName().flattenToString() + " , " + serviceComponent.flattenToString()); + isSystemProvider = mInfo.isSystemProvider(); } else { Slog.i(TAG, "newServiceInfoLocked, mInfo null, " + serviceComponent.flattenToString()); @@ -94,7 +101,7 @@ public final class CredentialManagerServiceImpl extends getPrimaryProvidersForUserId(mMaster.getContext(), mUserId); mInfo = CredentialProviderInfoFactory.create( getContext(), serviceComponent, - mUserId, /*isSystemProvider=*/false, + mUserId, isSystemProvider, primaryProviders.contains(serviceComponent)); return mInfo.getServiceInfo(); } @@ -148,15 +155,63 @@ public final class CredentialManagerServiceImpl extends * @param packageName package of the app being updated. */ @GuardedBy("mLock") + @SuppressWarnings("GuardedBy") // ErrorProne requires this.mMaster.mLock which is the case + // because this method is called by this.mMaster anyway protected void handlePackageUpdateLocked(@NonNull String packageName) { if (mInfo != null && mInfo.getServiceInfo() != null && mInfo.getServiceInfo().getComponentName() .getPackageName().equals(packageName)) { - try { - newServiceInfoLocked(mInfo.getServiceInfo().getComponentName()); - } catch (PackageManager.NameNotFoundException e) { - Slog.e(TAG, "Issue while updating serviceInfo: " + e.getMessage()); + if (Flags.packageUpdateFixEnabled()) { + try { + updateCredentialProviderInfo(mInfo.getServiceInfo().getComponentName(), + mInfo.isSystemProvider()); + } catch (SecurityException | PackageManager.NameNotFoundException + | NullPointerException e) { + Slog.w(TAG, "Unable to update provider, must be removed: " + e.getMessage()); + mMaster.handleServiceRemovedMultiModeLocked(mInfo.getComponentName(), mUserId); + } + } else { + try { + newServiceInfoLocked(mInfo.getServiceInfo().getComponentName()); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "Issue while updating serviceInfo: " + e.getMessage()); + } + } + } + } + + @GuardedBy("mLock") + private void updateCredentialProviderInfo(ComponentName componentName, boolean isSystemProvider) + throws SecurityException, PackageManager.NameNotFoundException { + Slog.d(TAG, "Updating credential provider: " + componentName.flattenToString()); + if (!isValidCredentialProviderInfo(componentName, mUserId, isSystemProvider)) { + throw new SecurityException("Service has not been set up correctly"); + } + newServiceInfoLocked(componentName); + } + + private boolean isValidCredentialProviderInfo(ComponentName componentName, int userId, + boolean isSystemProvider) { + Context context = getContext(); + if (context == null) { + return false; + } + String serviceInterface = CredentialProviderService.SERVICE_INTERFACE; + if (isSystemProvider) { + serviceInterface = CredentialProviderService.SYSTEM_SERVICE_INTERFACE; + } + final List<ResolveInfo> resolveInfos = + context.getPackageManager() + .queryIntentServicesAsUser( + new Intent(serviceInterface), + PackageManager.ResolveInfoFlags.of(PackageManager.GET_META_DATA), + userId); + for (ResolveInfo resolveInfo : resolveInfos) { + final ServiceInfo serviceInfo = resolveInfo.serviceInfo; + if (serviceInfo.getComponentName().equals(componentName)) { + return true; } } + return false; } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java index bbbfe0b2f0a2..5b7e7f17c454 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java @@ -65,6 +65,7 @@ import android.util.Log; import android.util.SparseArray; import android.util.Xml; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; @@ -120,11 +121,13 @@ final class DevicePolicyEngine { /** * Map of <userId, Map<policyKey, policyState>> */ + @GuardedBy("mLock") private final SparseArray<Map<PolicyKey, PolicyState<?>>> mLocalPolicies; /** * Map of <policyKey, policyState> */ + @GuardedBy("mLock") private final Map<PolicyKey, PolicyState<?>> mGlobalPolicies; /** @@ -152,6 +155,7 @@ final class DevicePolicyEngine { mAdminPolicySize = new SparseArray<>(); } + @GuardedBy("mLock") private void forceEnforcementRefreshIfUserRestrictionLocked( @NonNull PolicyDefinition<?> policyDefinition) { try { @@ -185,6 +189,7 @@ final class DevicePolicyEngine { return false; } + @GuardedBy("mLock") private void forceEnforcementRefreshLocked(PolicyDefinition<Boolean> policyDefinition) { Binder.withCleanCallingIdentity(() -> { // Sync global state @@ -296,6 +301,7 @@ final class DevicePolicyEngine { * * <p>Passing a {@code null} value means the policy set by this admin should be removed. */ + @GuardedBy("mLock") private <V> void setNonCoexistableLocalPolicyLocked( PolicyDefinition<V> policyDefinition, PolicyState<V> localPolicyState, @@ -440,6 +446,7 @@ final class DevicePolicyEngine { /** * Enforces the new policy and notifies relevant admins. */ + @GuardedBy("mLock") private <V> void onLocalPolicyChangedLocked( @NonNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, @@ -600,6 +607,7 @@ final class DevicePolicyEngine { /** * Enforces the new policy globally and notifies relevant admins. */ + @GuardedBy("mLock") private <V> void onGlobalPolicyChangedLocked( @NonNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin) { @@ -627,6 +635,7 @@ final class DevicePolicyEngine { * * <p>Returns {@code true} if the policy is enforced successfully on all users. */ + @GuardedBy("mLock") private <V> boolean applyGlobalPolicyOnUsersWithLocalPoliciesLocked( @NonNull PolicyDefinition<V> policyDefinition, @NonNull EnforcingAdmin enforcingAdmin, @@ -930,6 +939,7 @@ final class DevicePolicyEngine { removePoliciesForAdmin(oldAdmin); } + @GuardedBy("mLock") private Set<UserRestrictionPolicyKey> getUserRestrictionPolicyKeysForAdminLocked( Map<PolicyKey, PolicyState<?>> policies, EnforcingAdmin admin) { @@ -949,6 +959,7 @@ final class DevicePolicyEngine { return keys; } + @GuardedBy("mLock") private <V> boolean hasLocalPolicyLocked(PolicyDefinition<V> policyDefinition, int userId) { if (policyDefinition.isGlobalOnlyPolicy()) { return false; @@ -963,6 +974,7 @@ final class DevicePolicyEngine { .getPoliciesSetByAdmins().isEmpty(); } + @GuardedBy("mLock") private <V> boolean hasGlobalPolicyLocked(PolicyDefinition<V> policyDefinition) { if (policyDefinition.isLocalOnlyPolicy()) { return false; @@ -974,6 +986,7 @@ final class DevicePolicyEngine { .isEmpty(); } + @GuardedBy("mLock") @NonNull private <V> PolicyState<V> getLocalPolicyStateLocked( PolicyDefinition<V> policyDefinition, int userId) { @@ -993,6 +1006,7 @@ final class DevicePolicyEngine { return getPolicyStateLocked(mLocalPolicies.get(userId), policyDefinition); } + @GuardedBy("mLock") private <V> void removeLocalPolicyStateLocked( PolicyDefinition<V> policyDefinition, int userId) { if (!mLocalPolicies.contains(userId)) { @@ -1001,6 +1015,7 @@ final class DevicePolicyEngine { mLocalPolicies.get(userId).remove(policyDefinition.getPolicyKey()); } + @GuardedBy("mLock") @NonNull private <V> PolicyState<V> getGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition) { if (policyDefinition.isLocalOnlyPolicy()) { @@ -1015,10 +1030,12 @@ final class DevicePolicyEngine { return getPolicyStateLocked(mGlobalPolicies, policyDefinition); } + @GuardedBy("mLock") private <V> void removeGlobalPolicyStateLocked(PolicyDefinition<V> policyDefinition) { mGlobalPolicies.remove(policyDefinition.getPolicyKey()); } + @GuardedBy("mLock") private static <V> PolicyState<V> getPolicyStateLocked( Map<PolicyKey, PolicyState<?>> policies, PolicyDefinition<V> policyDefinition) { try { @@ -1089,6 +1106,7 @@ final class DevicePolicyEngine { } // TODO(b/261430877): Finalise the decision on which admins to send the updates to. + @GuardedBy("mLock") private <V> void sendPolicyChangedToAdminsLocked( PolicyState<V> policyState, EnforcingAdmin callingAdmin, @@ -1378,6 +1396,7 @@ final class DevicePolicyEngine { }); } + @GuardedBy("mLock") private <V> void enforcePolicyOnUserLocked(int userId, PolicyState<V> policyState) { if (!policyState.getPolicyDefinition().isInheritable()) { return; @@ -1509,6 +1528,7 @@ final class DevicePolicyEngine { * Called after an admin policy has been added to start binding to the admin if a connection * was not already established. */ + @GuardedBy("mLock") private void updateDeviceAdminServiceOnPolicyAddLocked(@NonNull EnforcingAdmin enforcingAdmin) { int userId = enforcingAdmin.getUserId(); @@ -1537,6 +1557,7 @@ final class DevicePolicyEngine { * Called after an admin policy has been removed to stop binding to the admin if they no longer * have any policies set. */ + @GuardedBy("mLock") private void updateDeviceAdminServiceOnPolicyRemoveLocked( @NonNull EnforcingAdmin enforcingAdmin) { if (doesAdminHavePoliciesLocked(enforcingAdmin)) { @@ -1562,6 +1583,7 @@ final class DevicePolicyEngine { /* actionForLog= */ "policy-removed"); } + @GuardedBy("mLock") private boolean doesAdminHavePoliciesLocked(@NonNull EnforcingAdmin enforcingAdmin) { for (PolicyKey policy : mGlobalPolicies.keySet()) { PolicyState<?> policyState = mGlobalPolicies.get(policy); @@ -1785,6 +1807,7 @@ final class DevicePolicyEngine { } } + @GuardedBy("mLock") <V> void reapplyAllPoliciesOnBootLocked() { for (PolicyKey policy : mGlobalPolicies.keySet()) { PolicyState<?> policyState = mGlobalPolicies.get(policy); @@ -1919,6 +1942,7 @@ final class DevicePolicyEngine { } } + @GuardedBy("mLock") void writeToFileLocked() { Log.d(TAG, "Writing to " + mFile); @@ -1931,7 +1955,7 @@ final class DevicePolicyEngine { out.startDocument(null, true); // Actual content - writeInner(out); + writeInnerLocked(out); out.endDocument(); out.flush(); @@ -1948,16 +1972,19 @@ final class DevicePolicyEngine { } } + @GuardedBy("mLock") // TODO(b/256846294): Add versioning to read/write - void writeInner(TypedXmlSerializer serializer) throws IOException { - writeLocalPoliciesInner(serializer); - writeGlobalPoliciesInner(serializer); - writeEnforcingAdminsInner(serializer); - writeEnforcingAdminSizeInner(serializer); - writeMaxPolicySizeInner(serializer); + void writeInnerLocked(TypedXmlSerializer serializer) throws IOException { + writeLocalPoliciesInnerLocked(serializer); + writeGlobalPoliciesInnerLocked(serializer); + writeEnforcingAdminsInnerLocked(serializer); + writeEnforcingAdminSizeInnerLocked(serializer); + writeMaxPolicySizeInnerLocked(serializer); } - private void writeLocalPoliciesInner(TypedXmlSerializer serializer) throws IOException { + @GuardedBy("mLock") + private void writeLocalPoliciesInnerLocked(TypedXmlSerializer serializer) + throws IOException { if (mLocalPolicies != null) { for (int i = 0; i < mLocalPolicies.size(); i++) { int userId = mLocalPolicies.keyAt(i); @@ -1981,7 +2008,9 @@ final class DevicePolicyEngine { } } - private void writeGlobalPoliciesInner(TypedXmlSerializer serializer) throws IOException { + @GuardedBy("mLock") + private void writeGlobalPoliciesInnerLocked(TypedXmlSerializer serializer) + throws IOException { if (mGlobalPolicies != null) { for (Map.Entry<PolicyKey, PolicyState<?>> policy : mGlobalPolicies.entrySet()) { serializer.startTag(/* namespace= */ null, TAG_GLOBAL_POLICY_ENTRY); @@ -1999,7 +2028,9 @@ final class DevicePolicyEngine { } } - private void writeEnforcingAdminsInner(TypedXmlSerializer serializer) throws IOException { + @GuardedBy("mLock") + private void writeEnforcingAdminsInnerLocked(TypedXmlSerializer serializer) + throws IOException { if (mEnforcingAdmins != null) { for (int i = 0; i < mEnforcingAdmins.size(); i++) { int userId = mEnforcingAdmins.keyAt(i); @@ -2012,7 +2043,8 @@ final class DevicePolicyEngine { } } - private void writeEnforcingAdminSizeInner(TypedXmlSerializer serializer) + @GuardedBy("mLock") + private void writeEnforcingAdminSizeInnerLocked(TypedXmlSerializer serializer) throws IOException { if (mAdminPolicySize != null) { for (int i = 0; i < mAdminPolicySize.size(); i++) { @@ -2034,7 +2066,8 @@ final class DevicePolicyEngine { } } - private void writeMaxPolicySizeInner(TypedXmlSerializer serializer) + @GuardedBy("mLock") + private void writeMaxPolicySizeInnerLocked(TypedXmlSerializer serializer) throws IOException { serializer.startTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT); serializer.attributeInt( @@ -2042,6 +2075,7 @@ final class DevicePolicyEngine { serializer.endTag(/* namespace= */ null, TAG_MAX_POLICY_SIZE_LIMIT); } + @GuardedBy("mLock") void readFromFileLocked() { if (!mFile.exists()) { Log.d(TAG, "" + mFile + " doesn't exist"); @@ -2055,7 +2089,7 @@ final class DevicePolicyEngine { input = f.openRead(); TypedXmlPullParser parser = Xml.resolvePullParser(input); - readInner(parser); + readInnerLocked(parser); } catch (XmlPullParserException | IOException | ClassNotFoundException e) { Slogf.wtf(TAG, "Error parsing resources file", e); @@ -2064,7 +2098,8 @@ final class DevicePolicyEngine { } } - private void readInner(TypedXmlPullParser parser) + @GuardedBy("mLock") + private void readInnerLocked(TypedXmlPullParser parser) throws IOException, XmlPullParserException, ClassNotFoundException { int outerDepth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, outerDepth)) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 191c21e661d0..aee32a0473a3 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -423,6 +423,7 @@ import android.database.ContentObserver; import android.database.Cursor; import android.graphics.Bitmap; import android.hardware.usb.UsbManager; +import android.health.connect.HealthConnectManager; import android.location.Location; import android.location.LocationManager; import android.media.AudioManager; @@ -2149,6 +2150,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); mBackgroundHandler = BackgroundThread.getHandler(); + // Add the health permission to the list of restricted permissions. + if (android.permission.flags.Flags.replaceBodySensorPermissionEnabled()) { + Set<String> healthPermissions = HealthConnectManager.getHealthPermissions(mContext); + for (String permission : healthPermissions) { + SENSOR_PERMISSIONS.add(permission); + } + } + // Needed when mHasFeature == false, because it controls the certificate warning text. mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 2bbd69c65eb8..e158310455ac 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1279,12 +1279,6 @@ public final class SystemServer implements Dumpable { if (!Flags.refactorCrashrecovery()) { // Initialize RescueParty. CrashRecoveryAdaptor.rescuePartyRegisterHealthObserver(mSystemContext); - if (!Flags.recoverabilityDetection()) { - // Now that we have the bare essentials of the OS up and running, take - // note that we just booted, which might send out a rescue party if - // we're stuck in a runtime restart loop. - CrashRecoveryAdaptor.packageWatchdogNoteBoot(mSystemContext); - } } @@ -1558,14 +1552,6 @@ public final class SystemServer implements Dumpable { boolean enableVrService = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE); - if (!Flags.recoverabilityDetection()) { - // For debugging RescueParty - if (Build.IS_DEBUGGABLE - && SystemProperties.getBoolean("debug.crash_system", false)) { - throw new RuntimeException(); - } - } - try { final String SECONDARY_ZYGOTE_PRELOAD = "SecondaryZygotePreload"; // We start the preload ~1s before the webview factory preparation, to @@ -3091,13 +3077,11 @@ public final class SystemServer implements Dumpable { CrashRecoveryAdaptor.initializeCrashrecoveryModuleService(mSystemServiceManager); t.traceEnd(); } else { - if (Flags.recoverabilityDetection()) { - // Now that we have the essential services needed for mitigations, register the boot - // with package watchdog. - // Note that we just booted, which might send out a rescue party if we're stuck in a - // runtime restart loop. - CrashRecoveryAdaptor.packageWatchdogNoteBoot(mSystemContext); - } + // Now that we have the essential services needed for mitigations, register the boot + // with package watchdog. + // Note that we just booted, which might send out a rescue party if we're stuck in a + // runtime restart loop. + CrashRecoveryAdaptor.packageWatchdogNoteBoot(mSystemContext); } t.traceBegin("MakeDisplayManagerServiceReady"); @@ -3511,12 +3495,10 @@ public final class SystemServer implements Dumpable { * are updated outside of OTA; and to avoid breaking dependencies from system into apexes. */ private void startApexServices(@NonNull TimingsTraceAndSlog t) { - if (Flags.recoverabilityDetection()) { - // For debugging RescueParty - if (Build.IS_DEBUGGABLE - && SystemProperties.getBoolean("debug.crash_system", false)) { - throw new RuntimeException(); - } + // For debugging RescueParty + if (Build.IS_DEBUGGABLE + && SystemProperties.getBoolean("debug.crash_system", false)) { + throw new RuntimeException(); } t.traceBegin("startApexServices"); diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java index 983e63bc325d..f731b50d81b4 100644 --- a/services/supervision/java/com/android/server/supervision/SupervisionService.java +++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java @@ -81,6 +81,25 @@ public class SupervisionService extends ISupervisionManager.Stub { } /** + * Creates an {@link Intent} that can be used with {@link Context#startActivity(Intent)} to + * launch the activity to verify supervision credentials. + * + * <p>A valid {@link Intent} is always returned if supervision is enabled at the time this + * method is called, the launched activity still need to perform validity checks as the + * supervision state can change when it's launched. A null intent is returned if supervision is + * disabled at the time of this method call. + * + * <p>A result code of {@link android.app.Activity#RESULT_OK} indicates successful verification + * of the supervision credentials. + */ + @Override + @Nullable + public Intent createConfirmSupervisionCredentialsIntent() { + // TODO(b/392961554): Implement createAuthenticationIntent API + throw new UnsupportedOperationException(); + } + + /** * Returns whether supervision is enabled for the given user. * * <p>Supervision is automatically enabled when the supervision app becomes the profile owner or diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java index 5d64cb638702..7bd836dc243b 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java @@ -34,16 +34,20 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; +import android.app.ActivityManager; import android.app.Instrumentation; import android.content.res.Configuration; import android.graphics.Insets; +import android.os.Build; import android.os.RemoteException; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.server.wm.WindowManagerStateHelper; import android.util.Log; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowInsetsAnimation; import android.view.WindowManagerGlobal; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.Flags; @@ -72,6 +76,7 @@ import org.junit.Test; import org.junit.rules.TestName; import org.junit.runner.RunWith; +import java.util.List; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -86,25 +91,36 @@ public class InputMethodServiceTest { "android:id/input_method_nav_back"; private static final String INPUT_METHOD_NAV_IME_SWITCHER_ID = "android:id/input_method_nav_ime_switcher"; - private static final long TIMEOUT_IN_SECONDS = 3; - private static final String ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD = - "settings put secure " + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD + " 1"; - private static final String DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD = - "settings put secure " + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD + " 0"; + + /** Timeout until the uiObject should be found. */ + private static final long TIMEOUT_MS = 5000L * Build.HW_TIMEOUT_MULTIPLIER; + + /** Timeout until the event is expected. */ + private static final long EXPECT_TIMEOUT_MS = 3000L * Build.HW_TIMEOUT_MULTIPLIER; + + /** Timeout during which the event is not expected. */ + private static final long NOT_EXCEPT_TIMEOUT_MS = 2000L * Build.HW_TIMEOUT_MULTIPLIER; + + /** Command to set showing the IME when a hardware keyboard is connected. */ + private static final String SET_SHOW_IME_WITH_HARD_KEYBOARD_CMD = + "settings put secure " + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD; + /** Command to get verbose ImeTracker logging state. */ + private static final String GET_VERBOSE_IME_TRACKER_LOGGING_CMD = + "getprop persist.debug.imetracker"; + /** Command to set verbose ImeTracker logging state. */ + private static final String SET_VERBOSE_IME_TRACKER_LOGGING_CMD = + "setprop persist.debug.imetracker"; /** The ids of the subtypes of SimpleIme. */ private static final int[] SUBTYPE_IDS = new int[]{1, 2}; - private final WindowManagerStateHelper mWmState = new WindowManagerStateHelper(); + private final WindowManagerStateHelper mWmState = new WindowManagerStateHelper(); private final GestureNavSwitchHelper mGestureNavSwitchHelper = new GestureNavSwitchHelper(); private final DeviceFlagsValueProvider mFlagsValueProvider = new DeviceFlagsValueProvider(); @Rule - public final CheckFlagsRule mCheckFlagsRule = new CheckFlagsRule(mFlagsValueProvider); - - @Rule public final TestName mName = new TestName(); private Instrumentation mInstrumentation; @@ -114,7 +130,8 @@ public class InputMethodServiceTest { private String mInputMethodId; private TestActivity mActivity; private InputMethodServiceWrapper mInputMethodService; - private boolean mShowImeWithHardKeyboardEnabled; + private boolean mOriginalVerboseImeTrackerLoggingEnabled; + private boolean mOriginalShowImeWithHardKeyboardEnabled; @Before public void setUp() throws Exception { @@ -123,9 +140,12 @@ public class InputMethodServiceTest { mImm = mInstrumentation.getContext().getSystemService(InputMethodManager.class); mTargetPackageName = mInstrumentation.getTargetContext().getPackageName(); mInputMethodId = getInputMethodId(); + mOriginalVerboseImeTrackerLoggingEnabled = getVerboseImeTrackerLogging(); + if (!mOriginalVerboseImeTrackerLoggingEnabled) { + setVerboseImeTrackerLogging(true); + } prepareIme(); prepareActivity(); - mInstrumentation.waitForIdleSync(); mUiDevice.freezeRotation(); mUiDevice.setOrientationNatural(); // Waits for input binding ready. @@ -148,17 +168,18 @@ public class InputMethodServiceTest { .that(mInputMethodService.getCurrentInputViewStarted()).isFalse(); }); // Save the original value of show_ime_with_hard_keyboard from Settings. - mShowImeWithHardKeyboardEnabled = + mOriginalShowImeWithHardKeyboardEnabled = mInputMethodService.getShouldShowImeWithHardKeyboardForTesting(); } @After public void tearDown() throws Exception { mUiDevice.unfreezeRotation(); + if (!mOriginalVerboseImeTrackerLoggingEnabled) { + setVerboseImeTrackerLogging(false); + } // Change back the original value of show_ime_with_hard_keyboard in Settings. - executeShellCommand(mShowImeWithHardKeyboardEnabled - ? ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD - : DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD); + setShowImeWithHardKeyboard(mOriginalShowImeWithHardKeyboardEnabled); executeShellCommand("ime disable " + mInputMethodId); } @@ -170,7 +191,7 @@ public class InputMethodServiceTest { public void testShowHideKeyboard_byUserAction() { waitUntilActivityReadyForInputInjection(mActivity); - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); // Performs click on EditText to bring up the IME. Log.i(TAG, "Click on EditText"); @@ -201,14 +222,12 @@ public class InputMethodServiceTest { */ @Test public void testShowHideKeyboard_byInputMethodManager() { - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); - // Triggers to show IME via public API. verifyInputViewStatusOnMainSync( () -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(), EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); - // Triggers to hide IME via public API. verifyInputViewStatusOnMainSync( () -> assertThat(mActivity.hideImeWithInputMethodManager(0 /* flags */)).isTrue(), EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown"); @@ -219,68 +238,86 @@ public class InputMethodServiceTest { */ @Test public void testShowHideKeyboard_byInsetsController() { - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); - // Triggers to show IME via public API. verifyInputViewStatusOnMainSync( () -> mActivity.showImeWithWindowInsetsController(), EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); - // Triggers to hide IME via public API. verifyInputViewStatusOnMainSync( () -> mActivity.hideImeWithWindowInsetsController(), EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown"); } /** + * This checks that the surface is removed after the window was hidden in + * InputMethodService#hideSoftInput + */ + @Test + @RequiresFlagsEnabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) + public void testSurfaceRemovedAfterHideSoftInput() { + setShowImeWithHardKeyboard(true /* enabled */); + + // Triggers to show IME via public API. + verifyInputViewStatusOnMainSync(() -> mActivity.showImeWithWindowInsetsController(), + EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + assertWithMessage("IME is shown").that(mInputMethodService.isInputViewShown()).isTrue(); + + final var window = mInputMethodService.getWindow().getWindow(); + assertWithMessage("IME window exists").that(window).isNotNull(); + assertWithMessage("IME window showing").that( + window.getDecorView().getVisibility()).isEqualTo(View.VISIBLE); + + mActivity.getWindow().getDecorView().setWindowInsetsAnimationCallback( + new WindowInsetsAnimation.Callback( + WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE) { + @NonNull + @Override + public WindowInsetsAnimation.Bounds onStart( + @NonNull WindowInsetsAnimation animation, + @NonNull WindowInsetsAnimation.Bounds bounds) { + return super.onStart(animation, bounds); + } + + @NonNull + @Override + public WindowInsets onProgress(@NonNull WindowInsets insets, + @NonNull List<WindowInsetsAnimation> runningAnimations) { + assertWithMessage("IME surface not removed during the animation").that( + window.getDecorView().getVisibility()).isEqualTo(View.VISIBLE); + return insets; + } + + @Override + public void onEnd(@NonNull WindowInsetsAnimation animation) { + assertWithMessage( + "IME surface not removed before the end of the animation").that( + window.getDecorView().getVisibility()).isEqualTo(View.VISIBLE); + super.onEnd(animation); + } + }); + + // Triggers to hide IME via public API. + verifyInputViewStatusOnMainSync(() -> mActivity.hideImeWithWindowInsetsController(), + EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown"); + eventually(() -> assertWithMessage("IME window not showing").that( + window.getDecorView().getVisibility()).isEqualTo(View.GONE)); + } + + /** * This checks the result of calling IMS#requestShowSelf and IMS#requestHideSelf. - * - * <p>With the refactor in b/298172246, all calls to IMMS#{show,hide}MySoftInputLocked - * will be just apply the requested visibility (by using the callback). Therefore, we will - * lose flags like HIDE_IMPLICIT_ONLY. */ @Test public void testShowHideSelf() { - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); - // IME request to show itself without any flags, expect shown. - Log.i(TAG, "Call IMS#requestShowSelf(0)"); verifyInputViewStatusOnMainSync( () -> mInputMethodService.requestShowSelf(0 /* flags */), EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); - if (!mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) { - // IME request to hide itself with flag HIDE_IMPLICIT_ONLY, expect not hide (shown). - Log.i(TAG, "Call IMS#requestHideSelf(InputMethodManager.HIDE_IMPLICIT_ONLY)"); - verifyInputViewStatusOnMainSync( - () -> mInputMethodService.requestHideSelf( - InputMethodManager.HIDE_IMPLICIT_ONLY), - EVENT_HIDE, false /* eventExpected */, true /* shown */, - "IME is still shown after HIDE_IMPLICIT_ONLY"); - } - - // IME request to hide itself without any flags, expect hidden. - Log.i(TAG, "Call IMS#requestHideSelf(0)"); verifyInputViewStatusOnMainSync( () -> mInputMethodService.requestHideSelf(0 /* flags */), EVENT_HIDE, true /* eventExpected */, false /* shown */, "IME is not shown"); - - if (!mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) { - // IME request to show itself with flag SHOW_IMPLICIT, expect shown. - Log.i(TAG, "Call IMS#requestShowSelf(InputMethodManager.SHOW_IMPLICIT)"); - verifyInputViewStatusOnMainSync( - () -> mInputMethodService.requestShowSelf(InputMethodManager.SHOW_IMPLICIT), - EVENT_SHOW, true /* eventExpected */, true /* shown */, - "IME is shown with SHOW_IMPLICIT"); - - // IME request to hide itself with flag HIDE_IMPLICIT_ONLY, expect hidden. - Log.i(TAG, "Call IMS#requestHideSelf(InputMethodManager.HIDE_IMPLICIT_ONLY)"); - verifyInputViewStatusOnMainSync( - () -> mInputMethodService.requestHideSelf( - InputMethodManager.HIDE_IMPLICIT_ONLY), - EVENT_HIDE, true /* eventExpected */, false /* shown */, - "IME is not shown after HIDE_IMPLICIT_ONLY"); - } } /** @@ -289,28 +326,25 @@ public class InputMethodServiceTest { */ @Test public void testOnEvaluateInputViewShown_showImeWithHardKeyboard() { - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); final var config = mInputMethodService.getResources().getConfiguration(); final var initialConfig = new Configuration(config); try { config.keyboard = Configuration.KEYBOARD_QWERTY; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO; - eventually(() -> - assertWithMessage("InputView should show with visible hardware keyboard") - .that(mInputMethodService.onEvaluateInputViewShown()).isTrue()); + assertWithMessage("InputView should show with visible hardware keyboard") + .that(mInputMethodService.onEvaluateInputViewShown()).isTrue(); config.keyboard = Configuration.KEYBOARD_NOKEYS; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO; - eventually(() -> - assertWithMessage("InputView should show without hardware keyboard") - .that(mInputMethodService.onEvaluateInputViewShown()).isTrue()); + assertWithMessage("InputView should show without hardware keyboard") + .that(mInputMethodService.onEvaluateInputViewShown()).isTrue(); config.keyboard = Configuration.KEYBOARD_QWERTY; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES; - eventually(() -> - assertWithMessage("InputView should show with hidden hardware keyboard") - .that(mInputMethodService.onEvaluateInputViewShown()).isTrue()); + assertWithMessage("InputView should show with hidden hardware keyboard") + .that(mInputMethodService.onEvaluateInputViewShown()).isTrue(); } finally { mInputMethodService.getResources() .updateConfiguration(initialConfig, null /* metrics */, null /* compat */); @@ -323,28 +357,25 @@ public class InputMethodServiceTest { */ @Test public void testOnEvaluateInputViewShown_disableShowImeWithHardKeyboard() { - setShowImeWithHardKeyboard(false /* enabled */); + setShowImeWithHardKeyboard(false /* enable */); final var config = mInputMethodService.getResources().getConfiguration(); final var initialConfig = new Configuration(config); try { config.keyboard = Configuration.KEYBOARD_QWERTY; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO; - eventually(() -> - assertWithMessage("InputView should not show with visible hardware keyboard") - .that(mInputMethodService.onEvaluateInputViewShown()).isFalse()); + assertWithMessage("InputView should not show with visible hardware keyboard") + .that(mInputMethodService.onEvaluateInputViewShown()).isFalse(); config.keyboard = Configuration.KEYBOARD_NOKEYS; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO; - eventually(() -> - assertWithMessage("InputView should show without hardware keyboard") - .that(mInputMethodService.onEvaluateInputViewShown()).isTrue()); + assertWithMessage("InputView should show without hardware keyboard") + .that(mInputMethodService.onEvaluateInputViewShown()).isTrue(); config.keyboard = Configuration.KEYBOARD_QWERTY; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES; - eventually(() -> - assertWithMessage("InputView should show with hidden hardware keyboard") - .that(mInputMethodService.onEvaluateInputViewShown()).isTrue()); + assertWithMessage("InputView should show with hidden hardware keyboard") + .that(mInputMethodService.onEvaluateInputViewShown()).isTrue(); } finally { mInputMethodService.getResources() .updateConfiguration(initialConfig, null /* metrics */, null /* compat */); @@ -357,7 +388,7 @@ public class InputMethodServiceTest { */ @Test public void testShowSoftInput_disableShowImeWithHardKeyboard() { - setShowImeWithHardKeyboard(false /* enabled */); + setShowImeWithHardKeyboard(false /* enable */); final var config = mInputMethodService.getResources().getConfiguration(); final var initialConfig = new Configuration(config); @@ -386,49 +417,17 @@ public class InputMethodServiceTest { } /** - * This checks that an explicit show request results in the IME being shown. - */ - @Test - public void testShowSoftInputExplicitly() { - setShowImeWithHardKeyboard(true /* enabled */); - - // When InputMethodService#onEvaluateInputViewShown() returns true and flag is EXPLICIT, the - // IME should be shown. - verifyInputViewStatusOnMainSync( - () -> assertThat(mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(), - EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); - } - - /** - * This checks that an implicit show request results in the IME being shown. - */ - @Test - public void testShowSoftInputImplicitly() { - setShowImeWithHardKeyboard(true /* enabled */); - - // When InputMethodService#onEvaluateInputViewShown() returns true and flag is IMPLICIT, - // the IME should be shown. - verifyInputViewStatusOnMainSync(() -> assertThat( - mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(), - EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); - } - - /** * This checks that an explicit show request when the IME is not previously shown, * and it should be shown in fullscreen mode, results in the IME being shown. */ @Test public void testShowSoftInputExplicitly_fullScreenMode() { - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); // Set orientation landscape to enable fullscreen mode. setOrientation(2); - eventually(() -> assertWithMessage("No longer in natural orientation") - .that(mUiDevice.isNaturalOrientation()).isFalse()); - // Wait for the TestActivity to be recreated. eventually(() -> assertWithMessage("Activity was re-created after rotation") .that(TestActivity.getInstance()).isNotEqualTo(mActivity)); - // Get the new TestActivity. mActivity = TestActivity.getInstance(); assertWithMessage("Re-created activity is not null").that(mActivity).isNotNull(); // Wait for the new EditText to be served by InputMethodManager. @@ -442,34 +441,40 @@ public class InputMethodServiceTest { /** * This checks that an implicit show request when the IME is not previously shown, - * and it should be shown in fullscreen mode, results in the IME not being shown. + * and it should be shown in fullscreen mode behaves like an explicit show request, resulting + * in the IME being shown. This is due to the refactor in b/298172246, causing us to lose flag + * information like {@link InputMethodManager#SHOW_IMPLICIT}. * - * <p>With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput - * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like - * SHOW_IMPLICIT. + * <p>Previously, an implicit show request when the IME is not previously shown, + * and it should be shown in fullscreen mode, would result in the IME not being shown. */ @Test - @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowSoftInputImplicitly_fullScreenMode() { - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); // Set orientation landscape to enable fullscreen mode. setOrientation(2); - eventually(() -> assertWithMessage("No longer in natural orientation") - .that(mUiDevice.isNaturalOrientation()).isFalse()); - // Wait for the TestActivity to be recreated. eventually(() -> assertWithMessage("Activity was re-created after rotation") .that(TestActivity.getInstance()).isNotEqualTo(mActivity)); - // Get the new TestActivity. mActivity = TestActivity.getInstance(); assertWithMessage("Re-created activity is not null").that(mActivity).isNotNull(); // Wait for the new EditText to be served by InputMethodManager. eventually(() -> assertWithMessage("Has an input connection to the re-created Activity") .that(mImm.hasActiveInputConnection(mActivity.getEditText())).isTrue()); - verifyInputViewStatusOnMainSync(() -> assertThat( - mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)).isTrue(), - EVENT_SHOW, false /* eventExpected */, false /* shown */, "IME is not shown"); + if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) { + verifyInputViewStatusOnMainSync(() -> assertThat( + mActivity.showImeWithInputMethodManager( + InputMethodManager.SHOW_IMPLICIT)) + .isTrue(), + EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + } else { + verifyInputViewStatusOnMainSync(() -> assertThat( + mActivity.showImeWithInputMethodManager( + InputMethodManager.SHOW_IMPLICIT)) + .isTrue(), + EVENT_SHOW, false /* eventExpected */, false /* shown */, "IME is not shown"); + } } /** @@ -478,7 +483,7 @@ public class InputMethodServiceTest { */ @Test public void testShowSoftInputExplicitly_withHardKeyboard() { - setShowImeWithHardKeyboard(false /* enabled */); + setShowImeWithHardKeyboard(false /* enable */); final var config = mInputMethodService.getResources().getConfiguration(); final var initialConfig = new Configuration(config); @@ -497,17 +502,17 @@ public class InputMethodServiceTest { } /** - * This checks that an implicit show request when a hardware keyboard is connected, - * results in the IME not being shown. + * This checks that an implicit show request when a hardware keyboard is connected behaves + * like an explicit show request, resulting in the IME being shown. This is due to the + * refactor in b/298172246, causing us to lose flag information like + * {@link InputMethodManager#SHOW_IMPLICIT}. * - * <p>With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput - * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like - * SHOW_IMPLICIT. + * <p>Previously, an implicit show request when a hardware keyboard is connected would + * result in the IME not being shown. */ @Test - @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowSoftInputImplicitly_withHardKeyboard() { - setShowImeWithHardKeyboard(false /* enabled */); + setShowImeWithHardKeyboard(false /* enable */); final var config = mInputMethodService.getResources().getConfiguration(); final var initialConfig = new Configuration(config); @@ -516,10 +521,20 @@ public class InputMethodServiceTest { config.keyboard = Configuration.KEYBOARD_QWERTY; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES; - verifyInputViewStatusOnMainSync(() ->assertThat( - mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT)) - .isTrue(), - EVENT_SHOW, false /* eventExpected */, false /* shown */, "IME is not shown"); + if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) { + verifyInputViewStatusOnMainSync(() -> assertThat( + mActivity.showImeWithInputMethodManager( + InputMethodManager.SHOW_IMPLICIT)) + .isTrue(), + EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + } else { + verifyInputViewStatusOnMainSync(() -> assertThat( + mActivity.showImeWithInputMethodManager( + InputMethodManager.SHOW_IMPLICIT)) + .isTrue(), + EVENT_SHOW, false /* eventExpected */, false /* shown */, + "IME is not shown"); + } } finally { mInputMethodService.getResources() .updateConfiguration(initialConfig, null /* metrics */, null /* compat */); @@ -532,7 +547,7 @@ public class InputMethodServiceTest { */ @Test public void testShowSoftInputExplicitly_thenConfigurationChanged() { - setShowImeWithHardKeyboard(false /* enabled */); + setShowImeWithHardKeyboard(false /* enable */); final var config = mInputMethodService.getResources().getConfiguration(); final var initialConfig = new Configuration(config); @@ -565,17 +580,17 @@ public class InputMethodServiceTest { /** * This checks that an implicit show request followed by connecting a hardware keyboard - * and a configuration change, does not trigger IMS#onFinishInputView, - * but results in the IME being hidden. + * and a configuration change behaves like an explicit show request, resulting in the IME + * still being shown. This is due to the refactor in b/298172246, causing us to lose flag + * information like {@link InputMethodManager#SHOW_IMPLICIT}. * - * <p>With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput - * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like - * SHOW_IMPLICIT. + * <p>Previously, an implicit show request followed by connecting a hardware keyboard + * and a configuration change, would not trigger IMS#onFinishInputView, but resulted in the + * IME being hidden. */ @Test - @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowSoftInputImplicitly_thenConfigurationChanged() { - setShowImeWithHardKeyboard(false /* enabled */); + setShowImeWithHardKeyboard(false /* enable */); final var config = mInputMethodService.getResources().getConfiguration(); final var initialConfig = new Configuration(config); @@ -596,16 +611,23 @@ public class InputMethodServiceTest { // Simulate a fake configuration change to avoid the recreation of TestActivity. config.orientation = Configuration.ORIENTATION_LANDSCAPE; - // Normally, IMS#onFinishInputView will be called when finishing the input view by - // the user. But if IMS#hideWindow is called when receiving a new configuration change, - // we don't expect that it's user-driven to finish the lifecycle of input view with - // IMS#onFinishInputView, because the input view will be re-initialized according - // to the last #mShowInputRequested state. So in this case we treat the input view as - // still alive. - verifyInputViewStatusOnMainSync( - () -> mInputMethodService.onConfigurationChanged(config), - EVENT_CONFIG, true /* eventExpected */, true /* inputViewStarted */, - false /* shown */, "IME is not shown after a configuration change"); + if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) { + verifyInputViewStatusOnMainSync( + () -> mInputMethodService.onConfigurationChanged(config), + EVENT_CONFIG, true /* eventExpected */, true /* shown */, + "IME is still shown after a configuration change"); + } else { + // Normally, IMS#onFinishInputView will be called when finishing the input view by + // the user. But if IMS#hideWindow is called when receiving a new configuration + // change, we don't expect that it's user-driven to finish the lifecycle of input + // view with IMS#onFinishInputView, because the input view will be re-initialized + // according to the last #mShowInputRequested state. So in this case we treat the + // input view as still alive. + verifyInputViewStatusOnMainSync( + () -> mInputMethodService.onConfigurationChanged(config), + EVENT_CONFIG, true /* eventExpected */, true /* inputViewStarted */, + false /* shown */, "IME is not shown after a configuration change"); + } } finally { mInputMethodService.getResources() .updateConfiguration(initialConfig, null /* metrics */, null /* compat */); @@ -619,7 +641,7 @@ public class InputMethodServiceTest { */ @Test public void testShowSoftInputExplicitly_thenShowSoftInputImplicitly_withHardKeyboard() { - setShowImeWithHardKeyboard(false /* enabled */); + setShowImeWithHardKeyboard(false /* enable */); final var config = mInputMethodService.getResources().getConfiguration(); final var initialConfig = new Configuration(config); @@ -628,12 +650,10 @@ public class InputMethodServiceTest { config.keyboard = Configuration.KEYBOARD_QWERTY; config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES; - // Explicit show request. verifyInputViewStatusOnMainSync(() -> assertThat( mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(), EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); - // Implicit show request. verifyInputViewStatusOnMainSync(() -> assertThat( mActivity.showImeWithInputMethodManager( InputMethodManager.SHOW_IMPLICIT)).isTrue(), @@ -654,17 +674,18 @@ public class InputMethodServiceTest { /** * This checks that a forced show request directly followed by an explicit show request, - * and then a hide not always request, still results in the IME being shown - * (i.e. the explicit show request retains the forced state). + * and then a not always hide request behaves like a normal hide request, resulting in the + * IME being hidden (i.e. the explicit show request does not retain the forced state). This is + * due to the refactor in b/298172246, causing us to lose flag information like + * {@link InputMethodManager#SHOW_FORCED}. * - * <p>With the refactor in b/298172246, all calls from InputMethodManager#{show,hide}SoftInput - * will be redirected to InsetsController#{show,hide}. Therefore, we will lose flags like - * HIDE_NOT_ALWAYS. + * <p>Previously, a forced show request directly followed by an explicit show request, + * and then a not always hide request, would result in the IME still being shown + * (i.e. the explicit show request would retain the forced state). */ @Test - @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_INSETS_CONTROLLER) public void testShowSoftInputForced_testShowSoftInputExplicitly_thenHideSoftInputNotAlways() { - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); verifyInputViewStatusOnMainSync(() -> assertThat( mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_FORCED)).isTrue(), @@ -674,11 +695,123 @@ public class InputMethodServiceTest { mActivity.showImeWithInputMethodManager(0 /* flags */)).isTrue(), EVENT_SHOW, false /* eventExpected */, true /* shown */, "IME is still shown"); - verifyInputViewStatusOnMainSync(() -> assertThat( - mActivity.hideImeWithInputMethodManager(InputMethodManager.HIDE_NOT_ALWAYS)) - .isTrue(), - EVENT_HIDE, false /* eventExpected */, true /* shown */, - "IME is still shown after HIDE_NOT_ALWAYS"); + if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) { + verifyInputViewStatusOnMainSync(() -> assertThat(mActivity + .hideImeWithInputMethodManager(InputMethodManager.HIDE_NOT_ALWAYS)) + .isTrue(), + EVENT_HIDE, true /* eventExpected */, false /* shown */, + "IME is not shown after HIDE_NOT_ALWAYS"); + } else { + verifyInputViewStatusOnMainSync(() -> assertThat(mActivity + .hideImeWithInputMethodManager(InputMethodManager.HIDE_NOT_ALWAYS)) + .isTrue(), + EVENT_HIDE, false /* eventExpected */, true /* shown */, + "IME is still shown after HIDE_NOT_ALWAYS"); + } + } + + /** + * This checks that an explicit show request followed by an implicit only hide request + * behaves like a normal hide request, resulting in the IME being hidden. This is due to + * the refactor in b/298172246, causing us to lose flag information like + * {@link InputMethodManager#SHOW_IMPLICIT} and {@link InputMethodManager#HIDE_IMPLICIT_ONLY}. + * + * <p>Previously, an explicit show request followed by an implicit only hide request + * would result in the IME still being shown. + */ + @Test + public void testShowSoftInputExplicitly_thenHideSoftInputImplicitOnly() { + setShowImeWithHardKeyboard(true /* enable */); + + verifyInputViewStatusOnMainSync( + () -> mActivity.showImeWithInputMethodManager(0 /* flags */), + EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + + if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) { + verifyInputViewStatusOnMainSync( + () -> mActivity.hideImeWithInputMethodManager( + InputMethodManager.HIDE_IMPLICIT_ONLY), + EVENT_HIDE, true /* eventExpected */, false /* shown */, + "IME is not shown after HIDE_IMPLICIT_ONLY"); + } else { + verifyInputViewStatusOnMainSync( + () -> mActivity.hideImeWithInputMethodManager( + InputMethodManager.HIDE_IMPLICIT_ONLY), + EVENT_HIDE, false /* eventExpected */, true /* shown */, + "IME is still shown after HIDE_IMPLICIT_ONLY"); + } + } + + /** + * This checks that an implicit show request followed by an implicit only hide request + * results in the IME being hidden. + */ + @Test + public void testShowSoftInputImplicitly_thenHideSoftInputImplicitOnly() { + setShowImeWithHardKeyboard(true /* enable */); + + verifyInputViewStatusOnMainSync( + () -> mActivity.showImeWithInputMethodManager(InputMethodManager.SHOW_IMPLICIT), + EVENT_SHOW, true /* eventExpected */, true /* shown */, + "IME is shown with SHOW_IMPLICIT"); + + verifyInputViewStatusOnMainSync( + () -> mActivity.hideImeWithInputMethodManager( + InputMethodManager.HIDE_IMPLICIT_ONLY), + EVENT_HIDE, true /* eventExpected */, false /* shown */, + "IME is not shown after HIDE_IMPLICIT_ONLY"); + } + + /** + * This checks that an explicit show self request followed by an implicit only hide self request + * behaves like a normal hide self request, resulting in the IME being hidden. This is due to + * the refactor in b/298172246, causing us to lose flag information like + * {@link InputMethodManager#SHOW_IMPLICIT} and {@link InputMethodManager#HIDE_IMPLICIT_ONLY}. + * + * <p>Previously, an explicit show self request followed by an implicit only hide self request + * would result in the IME still being shown. + */ + @Test + public void testShowSelfExplicitly_thenHideSelfImplicitOnly() { + setShowImeWithHardKeyboard(true /* enable */); + + verifyInputViewStatusOnMainSync( + () -> mInputMethodService.requestShowSelf(0 /* flags */), + EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + + if (mFlagsValueProvider.getBoolean(Flags.FLAG_REFACTOR_INSETS_CONTROLLER)) { + verifyInputViewStatusOnMainSync( + () -> mInputMethodService.requestHideSelf( + InputMethodManager.HIDE_IMPLICIT_ONLY), + EVENT_HIDE, true /* eventExpected */, false /* shown */, + "IME is not shown after HIDE_IMPLICIT_ONLY"); + } else { + verifyInputViewStatusOnMainSync( + () -> mInputMethodService.requestHideSelf( + InputMethodManager.HIDE_IMPLICIT_ONLY), + EVENT_HIDE, false /* eventExpected */, true /* shown */, + "IME is still shown after HIDE_IMPLICIT_ONLY"); + } + } + + /** + * This checks that an implicit show self request followed by an implicit only hide self request + * results in the IME being hidden. + */ + @Test + public void testShowSelfImplicitly_thenHideSelfImplicitOnly() { + setShowImeWithHardKeyboard(true /* enable */); + + verifyInputViewStatusOnMainSync( + () -> mInputMethodService.requestShowSelf(InputMethodManager.SHOW_IMPLICIT), + EVENT_SHOW, true /* eventExpected */, true /* shown */, + "IME is shown with SHOW_IMPLICIT"); + + verifyInputViewStatusOnMainSync( + () -> mInputMethodService.requestHideSelf( + InputMethodManager.HIDE_IMPLICIT_ONLY), + EVENT_HIDE, true /* eventExpected */, false /* shown */, + "IME is not shown after HIDE_IMPLICIT_ONLY"); } /** @@ -686,7 +819,7 @@ public class InputMethodServiceTest { */ @Test public void testFullScreenMode() { - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); Log.i(TAG, "Set orientation natural"); verifyFullscreenMode(() -> setOrientation(0), false /* eventExpected */, @@ -723,25 +856,22 @@ public class InputMethodServiceTest { public void testShowHideImeNavigationBar_doesDrawImeNavBar() { assumeTrue("Must have a navigation bar", hasNavigationBar()); - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); - // Show IME verifyInputViewStatusOnMainSync( () -> { - setDrawsImeNavBarAndSwitcherButton(true /* enabled */); + setDrawsImeNavBarAndSwitcherButton(true /* enable */); mActivity.showImeWithWindowInsetsController(); }, EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); assertWithMessage("IME navigation bar is initially shown") .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue(); - // Try to hide IME nav bar mInstrumentation.runOnMainSync(() -> setShowImeNavigationBar(false /* show */)); mInstrumentation.waitForIdleSync(); assertWithMessage("IME navigation bar is not shown after hide request") .that(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse(); - // Try to show IME nav bar mInstrumentation.runOnMainSync(() -> setShowImeNavigationBar(true /* show */)); mInstrumentation.waitForIdleSync(); assertWithMessage("IME navigation bar is shown after show request") @@ -758,25 +888,22 @@ public class InputMethodServiceTest { public void testShowHideImeNavigationBar_doesNotDrawImeNavBar() { assumeTrue("Must have a navigation bar", hasNavigationBar()); - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); - // Show IME verifyInputViewStatusOnMainSync( () -> { - setDrawsImeNavBarAndSwitcherButton(false /* enabled */); + setDrawsImeNavBarAndSwitcherButton(false /* enable */); mActivity.showImeWithWindowInsetsController(); }, EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); assertWithMessage("IME navigation bar is initially not shown") .that(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse(); - // Try to hide IME nav bar mInstrumentation.runOnMainSync(() -> setShowImeNavigationBar(false /* show */)); mInstrumentation.waitForIdleSync(); assertWithMessage("IME navigation bar is not shown after hide request") .that(mInputMethodService.isImeNavigationBarShownForTesting()).isFalse(); - // Try to show IME nav bar mInstrumentation.runOnMainSync(() -> setShowImeNavigationBar(true /* show */)); mInstrumentation.waitForIdleSync(); assertWithMessage("IME navigation bar is not shown after show request") @@ -792,13 +919,16 @@ public class InputMethodServiceTest { waitUntilActivityReadyForInputInjection(mActivity); - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); try (var ignored = mGestureNavSwitchHelper.withGestureNavigationMode()) { verifyInputViewStatusOnMainSync( () -> mActivity.showImeWithWindowInsetsController(), EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + eventually(() -> assertWithMessage("IME navigation bar is shown") + .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue()); + final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID)); verifyInputViewStatus( () -> { @@ -818,13 +948,16 @@ public class InputMethodServiceTest { waitUntilActivityReadyForInputInjection(mActivity); - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); try (var ignored = mGestureNavSwitchHelper.withGestureNavigationMode()) { verifyInputViewStatusOnMainSync( () -> mActivity.showImeWithWindowInsetsController(), EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + eventually(() -> assertWithMessage("IME navigation bar is shown") + .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue()); + final var backButton = getUiObject(By.res(INPUT_METHOD_NAV_BACK_ID)); verifyInputViewStatus( () -> { @@ -844,7 +977,7 @@ public class InputMethodServiceTest { waitUntilActivityReadyForInputInjection(mActivity); - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); final var info = mImm.getCurrentInputMethodInfo(); assertWithMessage("InputMethodInfo is not null").that(info).isNotNull(); @@ -855,11 +988,14 @@ public class InputMethodServiceTest { try (var ignored = mGestureNavSwitchHelper.withGestureNavigationMode()) { verifyInputViewStatusOnMainSync( () -> { - setDrawsImeNavBarAndSwitcherButton(true /* enabled */); + setDrawsImeNavBarAndSwitcherButton(true /* enable */); mActivity.showImeWithWindowInsetsController(); }, EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + eventually(() -> assertWithMessage("IME navigation bar is shown") + .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue()); + final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID)); imeSwitcherButton.click(); mInstrumentation.waitForIdleSync(); @@ -884,7 +1020,7 @@ public class InputMethodServiceTest { waitUntilActivityReadyForInputInjection(mActivity); - setShowImeWithHardKeyboard(true /* enabled */); + setShowImeWithHardKeyboard(true /* enable */); final var info = mImm.getCurrentInputMethodInfo(); assertWithMessage("InputMethodInfo is not null").that(info).isNotNull(); @@ -893,11 +1029,14 @@ public class InputMethodServiceTest { try (var ignored = mGestureNavSwitchHelper.withGestureNavigationMode()) { verifyInputViewStatusOnMainSync( () -> { - setDrawsImeNavBarAndSwitcherButton(true /* enabled */); + setDrawsImeNavBarAndSwitcherButton(true /* enable */); mActivity.showImeWithWindowInsetsController(); }, EVENT_SHOW, true /* eventExpected */, true /* shown */, "IME is shown"); + eventually(() -> assertWithMessage("IME navigation bar is shown") + .that(mInputMethodService.isImeNavigationBarShownForTesting()).isTrue()); + final var imeSwitcherButton = getUiObject(By.res(INPUT_METHOD_NAV_IME_SWITCHER_ID)); imeSwitcherButton.longClick(); mInstrumentation.waitForIdleSync(); @@ -956,7 +1095,8 @@ public class InputMethodServiceTest { runnable.run(); } mInstrumentation.waitForIdleSync(); - eventCalled = latch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS); + eventCalled = latch.await(eventExpected ? EXPECT_TIMEOUT_MS : NOT_EXCEPT_TIMEOUT_MS, + TimeUnit.MILLISECONDS); } catch (InterruptedException e) { fail("Interrupted while waiting for latch: " + e.getMessage()); return; @@ -1016,10 +1156,8 @@ public class InputMethodServiceTest { verifyInputViewStatus(runnable, EVENT_CONFIG, eventExpected, false /* shown */, "IME is not shown"); if (eventExpected) { - // Wait for the TestActivity to be recreated. eventually(() -> assertWithMessage("Activity was re-created after rotation") .that(TestActivity.getInstance()).isNotEqualTo(mActivity)); - // Get the new TestActivity. mActivity = TestActivity.getInstance(); assertWithMessage("Re-created activity is not null").that(mActivity).isNotNull(); // Wait for the new EditText to be served by InputMethodManager. @@ -1062,6 +1200,7 @@ public class InputMethodServiceTest { private void prepareActivity() { mActivity = TestActivity.startSync(mInstrumentation); + mInstrumentation.waitForIdleSync(); Log.i(TAG, "Finish preparing activity with editor."); } @@ -1086,21 +1225,51 @@ public class InputMethodServiceTest { * @param enable the value to be set. */ private void setShowImeWithHardKeyboard(boolean enable) { + if (mInputMethodService == null) { + // If the IME is no longer around, reset the setting unconditionally. + executeShellCommand(SET_SHOW_IME_WITH_HARD_KEYBOARD_CMD + " " + (enable ? "1" : "0")); + return; + } + final boolean currentEnabled = mInputMethodService.getShouldShowImeWithHardKeyboardForTesting(); if (currentEnabled != enable) { - executeShellCommand(enable - ? ENABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD - : DISABLE_SHOW_IME_WITH_HARD_KEYBOARD_CMD); + executeShellCommand(SET_SHOW_IME_WITH_HARD_KEYBOARD_CMD + " " + (enable ? "1" : "0")); eventually(() -> assertWithMessage("showImeWithHardKeyboard updated") .that(mInputMethodService.getShouldShowImeWithHardKeyboardForTesting()) .isEqualTo(enable)); } } - private static void executeShellCommand(@NonNull String cmd) { + /** + * Gets the verbose logging state in {@link android.view.inputmethod.ImeTracker}. + * + * @return {@code true} iff verbose logging is enabled. + */ + private static boolean getVerboseImeTrackerLogging() { + return executeShellCommand(GET_VERBOSE_IME_TRACKER_LOGGING_CMD).trim().equals("1"); + } + + /** + * Sets verbose logging in {@link android.view.inputmethod.ImeTracker}. + * + * @param enabled whether to enable or disable verbose logging. + * + * @implNote This must use {@link ActivityManager#notifySystemPropertiesChanged()} to listen + * for changes to the system property for the verbose ImeTracker logging. + */ + private void setVerboseImeTrackerLogging(boolean enabled) { + final var context = mInstrumentation.getContext(); + final var am = context.getSystemService(ActivityManager.class); + + executeShellCommand(SET_VERBOSE_IME_TRACKER_LOGGING_CMD + " " + (enabled ? "1" : "0")); + am.notifySystemPropertiesChanged(); + } + + @NonNull + private static String executeShellCommand(@NonNull String cmd) { Log.i(TAG, "Run command: " + cmd); - SystemUtil.runShellCommandOrThrow(cmd); + return SystemUtil.runShellCommandOrThrow(cmd); } /** @@ -1113,8 +1282,7 @@ public class InputMethodServiceTest { @NonNull private UiObject2 getUiObject(@NonNull BySelector bySelector) { - final var uiObject = mUiDevice.wait(Until.findObject(bySelector), - TimeUnit.SECONDS.toMillis(TIMEOUT_IN_SECONDS)); + final var uiObject = mUiDevice.wait(Until.findObject(bySelector), TIMEOUT_MS); assertWithMessage("UiObject with " + bySelector + " was found").that(uiObject).isNotNull(); return uiObject; } @@ -1137,10 +1305,10 @@ public class InputMethodServiceTest { * * <p>Note, neither of these are normally drawn when in three button navigation mode. * - * @param enabled whether the IME nav bar and IME Switcher button are drawn. + * @param enable whether the IME nav bar and IME Switcher button are drawn. */ - private void setDrawsImeNavBarAndSwitcherButton(boolean enabled) { - final int flags = enabled ? IME_DRAWS_IME_NAV_BAR | SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0; + private void setDrawsImeNavBarAndSwitcherButton(boolean enable) { + final int flags = enable ? IME_DRAWS_IME_NAV_BAR | SHOW_IME_SWITCHER_WHEN_IME_IS_SHOWN : 0; mInputMethodService.getInputMethodInternal().onNavButtonFlagsChanged(flags); } diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java index 558d1a7c4e8b..d4d4dcaa4f48 100644 --- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java +++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/src/com/android/apps/inputmethod/simpleime/ims/InputMethodServiceWrapper.java @@ -111,12 +111,6 @@ public class InputMethodServiceWrapper extends InputMethodService { } @Override - public void requestHideSelf(int flags) { - Log.i(TAG, "requestHideSelf() " + flags); - super.requestHideSelf(flags); - } - - @Override public void onConfigurationChanged(Configuration newConfig) { Log.i(TAG, "onConfigurationChanged() " + newConfig); super.onConfigurationChanged(newConfig); diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java index 7d25acd7f5e7..a42116351c2d 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java @@ -152,7 +152,7 @@ public class AutomaticBrightnessControllerTest { } @Override - AutomaticBrightnessController.Clock createClock(boolean isEnabled) { + AutomaticBrightnessController.Clock createClock() { return new AutomaticBrightnessController.Clock() { @Override public long uptimeMillis() { @@ -618,39 +618,46 @@ public class AutomaticBrightnessControllerTest { long increment = 500; // set autobrightness to low // t = 0 - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); // t = 500 mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); // t = 1000 mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(0.0f, mController.getAmbientLux(), EPSILON); // t = 1500 mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(0.0f, mController.getAmbientLux(), EPSILON); // t = 2000 // ensure that our reading is at 0. mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(0.0f, mController.getAmbientLux(), EPSILON); // t = 2500 // first 10000 lux sensor event reading mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertTrue(mController.getAmbientLux() > 0.0f); assertTrue(mController.getAmbientLux() < 10000.0f); // t = 3000 // lux reading should still not yet be 10000. mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertTrue(mController.getAmbientLux() > 0.0f); assertTrue(mController.getAmbientLux() < 10000.0f); @@ -659,45 +666,53 @@ public class AutomaticBrightnessControllerTest { // lux has been high (10000) for 1000ms. // lux reading should be 10000 // short horizon (ambient lux) is high, long horizon is still not high - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(10000.0f, mController.getAmbientLux(), EPSILON); // t = 4000 // stay high mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(10000.0f, mController.getAmbientLux(), EPSILON); // t = 4500 Mockito.clearInvocations(mBrightnessMappingStrategy); mClock.fastForward(increment); // short horizon is high, long horizon is high too - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 10000, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); verify(mBrightnessMappingStrategy, times(1)).getBrightness(10000, null, -1); assertEquals(10000.0f, mController.getAmbientLux(), EPSILON); // t = 5000 mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertTrue(mController.getAmbientLux() > 0.0f); assertTrue(mController.getAmbientLux() < 10000.0f); // t = 5500 mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertTrue(mController.getAmbientLux() > 0.0f); assertTrue(mController.getAmbientLux() < 10000.0f); // t = 6000 mClock.fastForward(increment); // ambient lux goes to 0 - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(0.0f, mController.getAmbientLux(), EPSILON); // only the values within the horizon should be kept assertArrayEquals(new float[] {10000, 10000, 0, 0, 0}, mController.getLastSensorValues(), EPSILON); - assertArrayEquals(new long[] {4000, 4500, 5000, 5500, 6000}, + assertArrayEquals(new long[]{4000 + ANDROID_SLEEP_TIME, 4500 + ANDROID_SLEEP_TIME, + 5000 + ANDROID_SLEEP_TIME, 5500 + ANDROID_SLEEP_TIME, + 6000 + ANDROID_SLEEP_TIME}, mController.getLastSensorTimestamps()); } @@ -793,7 +808,8 @@ public class AutomaticBrightnessControllerTest { for (int i = 0; i < 1000; i++) { lux += increment; mClock.fastForward(increment); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); } int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment + 1); @@ -807,17 +823,17 @@ public class AutomaticBrightnessControllerTest { long sensorTimestamp = mClock.now(); for (int i = valuesCount - 1; i >= 1; i--) { assertEquals(lux, sensorValues[i], EPSILON); - assertEquals(sensorTimestamp, sensorTimestamps[i]); + assertEquals(sensorTimestamp + ANDROID_SLEEP_TIME, sensorTimestamps[i]); lux -= increment; sensorTimestamp -= increment; } assertEquals(lux, sensorValues[0], EPSILON); - assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]); + assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG + ANDROID_SLEEP_TIME, + sensorTimestamps[0]); } @Test public void testAmbientLuxBuffers_prunedBeyondLongHorizonExceptLatestValue() throws Exception { - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass(SensorEventListener.class); verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), @@ -867,7 +883,8 @@ public class AutomaticBrightnessControllerTest { for (int i = 0; i < 20; i++) { lux += increment1; mClock.fastForward(increment1); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); } int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment1 + 1); @@ -877,7 +894,8 @@ public class AutomaticBrightnessControllerTest { for (int i = 0; i < initialCapacity - valuesCount; i++) { lux += increment2; mClock.fastForward(increment2); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); } float[] sensorValues = mController.getLastSensorValues(); @@ -890,7 +908,7 @@ public class AutomaticBrightnessControllerTest { long sensorTimestamp = mClock.now(); for (int i = initialCapacity - 1; i >= 1; i--) { assertEquals(lux, sensorValues[i], EPSILON); - assertEquals(sensorTimestamp, sensorTimestamps[i]); + assertEquals(sensorTimestamp + ANDROID_SLEEP_TIME, sensorTimestamps[i]); if (i >= valuesCount) { lux -= increment2; @@ -901,7 +919,8 @@ public class AutomaticBrightnessControllerTest { } } assertEquals(lux, sensorValues[0], EPSILON); - assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]); + assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG + ANDROID_SLEEP_TIME, + sensorTimestamps[0]); } @Test @@ -951,25 +970,29 @@ public class AutomaticBrightnessControllerTest { // t = 0 // Initial lux - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(500, mController.getAmbientLux(), EPSILON); // t = 1000 // Lux isn't steady yet mClock.fastForward(1000); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(500, mController.getAmbientLux(), EPSILON); // t = 1500 // Lux isn't steady yet mClock.fastForward(500); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(500, mController.getAmbientLux(), EPSILON); // t = 2500 // Lux is steady now mClock.fastForward(1000); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(1200, mController.getAmbientLux(), EPSILON); } @@ -992,25 +1015,29 @@ public class AutomaticBrightnessControllerTest { // t = 0 // Initial lux - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(1200, mController.getAmbientLux(), EPSILON); // t = 2000 // Lux isn't steady yet mClock.fastForward(2000); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(1200, mController.getAmbientLux(), EPSILON); // t = 2500 // Lux isn't steady yet mClock.fastForward(500); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(1200, mController.getAmbientLux(), EPSILON); // t = 4500 // Lux is steady now mClock.fastForward(2000); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(500, mController.getAmbientLux(), EPSILON); } @@ -1031,19 +1058,22 @@ public class AutomaticBrightnessControllerTest { // t = 0 // Initial lux - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(500, mController.getAmbientLux(), EPSILON); // t = 500 // Lux isn't steady yet mClock.fastForward(500); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(500, mController.getAmbientLux(), EPSILON); // t = 1500 // Lux is steady now mClock.fastForward(1000); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(1200, mController.getAmbientLux(), EPSILON); } @@ -1068,19 +1098,22 @@ public class AutomaticBrightnessControllerTest { // t = 0 // Initial lux - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1200, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(1200, mController.getAmbientLux(), EPSILON); // t = 1000 // Lux isn't steady yet mClock.fastForward(1000); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(1200, mController.getAmbientLux(), EPSILON); // t = 2500 // Lux is steady now mClock.fastForward(1500); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500)); + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500, + (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER)); assertEquals(500, mController.getAmbientLux(), EPSILON); } diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index e0e44252a8f3..c151732cec66 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -984,8 +984,7 @@ public class DisplayManagerServiceTest { Handler handler = displayManager.getDisplayHandler(); waitForIdleHandler(handler); - assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_BASIC_CHANGED, - EVENT_DISPLAY_REFRESH_RATE_CHANGED); + assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_BASIC_CHANGED); } /** diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java index aed1f9858660..db94958f769e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -1066,7 +1066,6 @@ public final class DisplayPowerControllerTest { com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true); - when(mDisplayManagerFlagsMock.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); @@ -1172,7 +1171,6 @@ public final class DisplayPowerControllerTest { com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true); - when(mDisplayManagerFlagsMock.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(false); mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java index 2ebb6c2a3ce4..ef39167dbabc 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java @@ -240,7 +240,6 @@ public final class DisplayBrightnessStrategySelectorTest { @Test public void selectStrategyDoesNotSelectDozeStrategyWhenOffloadSessionAutoBrightnessIsEnabled() { - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( @@ -378,7 +377,6 @@ public final class DisplayBrightnessStrategySelectorTest { @Test public void selectStrategy_selectsAutomaticStrategyWhenValid() { when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true); - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( @@ -409,7 +407,6 @@ public final class DisplayBrightnessStrategySelectorTest { @Test public void selectStrategy_doesNotSelectAutomaticStrategyWhenStylusInUse() { when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true); - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( @@ -536,7 +533,6 @@ public final class DisplayBrightnessStrategySelectorTest { @Test public void setAllowAutoBrightnessWhileDozing_enabledWhenConfigAndOffloadSessionAreEnabled() { - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( @@ -550,7 +546,6 @@ public final class DisplayBrightnessStrategySelectorTest { @Test public void setAllowAutoBrightnessWhileDozing_disabledWhenOffloadSessionFlagIsDisabled() { - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(false); when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( @@ -564,7 +559,6 @@ public final class DisplayBrightnessStrategySelectorTest { @Test public void setAllowAutoBrightnessWhileDozing_disabledWhenABWhileDozingConfigIsDisabled() { - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true); when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( @@ -588,7 +582,6 @@ public final class DisplayBrightnessStrategySelectorTest { @Test public void setAllowAutoBrightnessWhileDozing_EnabledWhenFlagsAreDisabled() { - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true); when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn( true); mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, @@ -600,11 +593,5 @@ public final class DisplayBrightnessStrategySelectorTest { mDisplayBrightnessStrategySelector .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession); assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing()); - - when(mDisplayManagerFlags.isDisplayOffloadEnabled()).thenReturn(true); - when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(false); - mDisplayBrightnessStrategySelector - .setAllowAutoBrightnessWhileDozing(mDisplayOffloadSession); - assertTrue(mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozing()); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java index db04d39e772c..eda5e8613dba 100644 --- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java @@ -23,7 +23,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString; 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.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.android.server.PackageWatchdog.MITIGATION_RESULT_SKIPPED; import static com.android.server.PackageWatchdog.MITIGATION_RESULT_SUCCESS; @@ -34,8 +33,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import android.content.ContentResolver; @@ -43,13 +40,8 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; -import android.crashrecovery.flags.Flags; import android.os.RecoverySystem; import android.os.SystemProperties; -import android.os.UserHandle; -import android.platform.test.annotations.EnableFlags; -import android.platform.test.flag.junit.FlagsParameterization; -import android.platform.test.flag.junit.SetFlagsRule; import android.provider.DeviceConfig; import android.provider.Settings; @@ -60,14 +52,8 @@ import com.android.server.am.SettingsToPropertiesMapper; import org.junit.After; import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; import org.mockito.Answers; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; @@ -76,34 +62,19 @@ import org.mockito.stubbing.Answer; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.concurrent.TimeUnit; /** * Test RescueParty. */ -@RunWith(Parameterized.class) public class RescuePartyTest { - @Rule - public SetFlagsRule mSetFlagsRule; private static final long CURRENT_NETWORK_TIME_MILLIS = 0L; - private static final String FAKE_NATIVE_NAMESPACE1 = "native1"; - private static final String FAKE_NATIVE_NAMESPACE2 = "native2"; - private static final String[] FAKE_RESET_NATIVE_NAMESPACES = - {FAKE_NATIVE_NAMESPACE1, FAKE_NATIVE_NAMESPACE2}; private static VersionedPackage sFailingPackage = new VersionedPackage("com.package.name", 1); private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue"; - private static final String CALLING_PACKAGE1 = "com.package.name1"; - private static final String CALLING_PACKAGE2 = "com.package.name2"; - private static final String CALLING_PACKAGE3 = "com.package.name3"; private static final String PERSISTENT_PACKAGE = "com.persistent.package"; private static final String NON_PERSISTENT_PACKAGE = "com.nonpersistent.package"; - private static final String NAMESPACE1 = "namespace1"; - private static final String NAMESPACE2 = "namespace2"; - private static final String NAMESPACE3 = "namespace3"; - private static final String NAMESPACE4 = "namespace4"; private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG = "persist.device_config.configuration.disable_rescue_party"; private static final String PROP_DISABLE_FACTORY_RESET_FLAG = @@ -127,22 +98,6 @@ public class RescuePartyTest { // Mock only sysprop apis private PackageWatchdog.BootThreshold mSpyBootThreshold; - @Captor - private ArgumentCaptor<DeviceConfig.MonitorCallback> mMonitorCallbackCaptor; - @Captor - private ArgumentCaptor<List<String>> mPackageListCaptor; - - @Parameters(name = "{0}") - public static List<FlagsParameterization> getFlags() { - return FlagsParameterization.allCombinationsOf( - Flags.FLAG_RECOVERABILITY_DETECTION, - Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS); - } - - public RescuePartyTest(FlagsParameterization flags) { - mSetFlagsRule = new SetFlagsRule(flags); - } - @Before public void setUp() throws Exception { mSession = @@ -248,7 +203,6 @@ public class RescuePartyTest { } @Test - @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testBootLoopNoFlags() { // this is old test where the flag needs to be disabled noteBoot(1); @@ -260,7 +214,6 @@ public class RescuePartyTest { } @Test - @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testPersistentAppCrashNoFlags() { // this is old test where the flag needs to be disabled noteAppCrash(1, true); @@ -396,7 +349,6 @@ public class RescuePartyTest { } @Test - @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testHealthCheckLevelsNoFlags() { // this is old test where the flag needs to be disabled RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); @@ -416,7 +368,6 @@ public class RescuePartyTest { } @Test - @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testBootLoopLevelsNoFlags() { RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext); @@ -425,25 +376,6 @@ public class RescuePartyTest { } - private void verifySettingsResets(int resetMode, String[] resetNamespaces, - HashMap<String, Integer> configResetVerifiedTimesMap) { - verifyOnlySettingsReset(resetMode); - } - - private void verifyOnlySettingsReset(int resetMode) { - verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null, - resetMode, UserHandle.USER_SYSTEM)); - verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(), - eq(resetMode), anyInt())); - } - - private void verifyNoSettingsReset(int resetMode) { - verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null, - resetMode, UserHandle.USER_SYSTEM), never()); - verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(), - eq(resetMode), anyInt()), never()); - } - private void noteBoot(int mitigationCount) { RescuePartyObserver.getInstance(mMockContext).onExecuteBootLoopMitigation(mitigationCount); } diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java index 5ddd8a50135b..2e315ecd7b37 100644 --- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java @@ -26,7 +26,10 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.role.RoleManager; +import android.companion.AssociationRequest; import android.content.pm.PackageManagerInternal; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; @@ -54,6 +57,7 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; import java.util.Set; @SmallTest @@ -74,6 +78,7 @@ public class SensitiveContentProtectionManagerServiceContentTest { @Mock private WindowManagerInternal mWindowManager; @Mock private MediaProjectionManager mProjectionManager; @Mock private PackageManagerInternal mPackageManagerInternal; + @Mock private RoleManager mRoleManager; private MediaProjectionInfo mMediaProjectionInfo; @Captor @@ -93,7 +98,8 @@ public class SensitiveContentProtectionManagerServiceContentTest { mSensitiveContentProtectionManagerService = new SensitiveContentProtectionManagerService(mContext); mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager, - mPackageManagerInternal, new ArraySet<>(Set.of(mExemptedScreenRecorderPackage))); + mPackageManagerInternal, mRoleManager, + new ArraySet<>(Set.of(mExemptedScreenRecorderPackage))); verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any()); mMediaPorjectionCallback = mMediaProjectionCallbackCaptor.getValue(); mMediaProjectionInfo = @@ -152,7 +158,7 @@ public class SensitiveContentProtectionManagerServiceContentTest { String testAutofillService = mScreenRecorderPackage + "/com.example.SampleAutofillService"; int userId = Process.myUserHandle().getIdentifier(); Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.AUTOFILL_SERVICE, testAutofillService , userId); + Settings.Secure.AUTOFILL_SERVICE, testAutofillService, userId); mMediaPorjectionCallback.onStart(mMediaProjectionInfo); mSensitiveContentProtectionManagerService.setSensitiveContentProtection( @@ -169,6 +175,19 @@ public class SensitiveContentProtectionManagerServiceContentTest { verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); } + @Test + public void testAppStreamingRoleHolderExemption() { + when(mRoleManager.getRoleHoldersAsUser( + AssociationRequest.DEVICE_PROFILE_APP_STREAMING, + mMediaProjectionInfo.getUserHandle())).thenReturn( + List.of(mMediaProjectionInfo.getPackageName())); + + mMediaPorjectionCallback.onStart(mMediaProjectionInfo); + mSensitiveContentProtectionManagerService.setSensitiveContentProtection( + mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true); + verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); + } + private void mockDisabledViaDeveloperOption() { Settings.Global.putInt( mContext.getContentResolver(), diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java index 32135f1cb7fa..3c6e18f822af 100644 --- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java @@ -33,6 +33,8 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.role.RoleManager; +import android.companion.AssociationRequest; import android.content.pm.PackageManagerInternal; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; @@ -67,6 +69,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.List; import java.util.Set; @SmallTest @@ -116,6 +119,9 @@ public class SensitiveContentProtectionManagerServiceNotificationTest { private PackageManagerInternal mPackageManagerInternal; @Mock + private RoleManager mRoleManager; + + @Mock private StatusBarNotification mNotification1; @Mock @@ -161,7 +167,8 @@ public class SensitiveContentProtectionManagerServiceNotificationTest { setupSensitiveNotification(); mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager, - mPackageManagerInternal, new ArraySet<>(Set.of(EXEMPTED_SCREEN_RECORDER_PACKAGE))); + mPackageManagerInternal, mRoleManager, + new ArraySet<>(Set.of(EXEMPTED_SCREEN_RECORDER_PACKAGE))); // Obtain useful mMediaProjectionCallback verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any()); @@ -315,6 +322,18 @@ public class SensitiveContentProtectionManagerServiceNotificationTest { } @Test + public void mediaProjectionOnStart_verifyExemptedAppStreamingPackage() { + MediaProjectionInfo mediaProjectionInfo = createMediaProjectionInfo(); + when(mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING, + mediaProjectionInfo.getUserHandle())).thenReturn( + List.of(mediaProjectionInfo.getPackageName())); + + mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); + + verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); + } + + @Test public void mediaProjectionOnStart_verifyExemptedRecorderPackage() { MediaProjectionInfo mediaProjectionInfo = createExemptMediaProjectionInfo(); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java index fa5847560782..4b53f1309337 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java @@ -23,18 +23,11 @@ import static com.android.server.am.ActivityManagerService.Injector; import static com.google.common.truth.Truth.assertThat; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import android.app.ActivityManagerInternal; import android.app.ActivityManagerInternal.FrozenProcessListener; import android.content.ComponentName; import android.content.Context; @@ -44,14 +37,12 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.MessageQueue; import android.os.Process; -import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.text.TextUtils; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.internal.annotations.GuardedBy; import com.android.modules.utils.testing.ExtendedMockitoRule; import com.android.modules.utils.testing.TestableDeviceConfig; import com.android.server.LocalServices; @@ -68,11 +59,9 @@ import org.mockito.Mock; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; /** @@ -164,7 +153,7 @@ public final class CachedAppOptimizerTest { app.info.uid = packageUid; // Exact value does not mater, it can be any state for which compaction is allowed. app.mState.setSetProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); - app.mState.setSetAdj(899); + app.mState.setSetAdj(940); app.mState.setCurAdj(940); return app; } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 1ef758cf192e..340115a7d465 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -3337,6 +3337,108 @@ public class MockingOomAdjusterTests { followUpTimeCaptor.capture()); } + /** + * For Perceptible Tasks adjustment, this solely unit-tests OomAdjuster -> onOtherActivity() + */ + @SuppressWarnings("GuardedBy") + @Test + @EnableFlags(Flags.FLAG_PERCEPTIBLE_TASKS) + public void testPerceptibleAdjustment() { + ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, + MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); + + long now = mInjector.getUptimeMillis(); + + // GIVEN: perceptible adjustment is NOT enabled (perceptible stop time is not set) + // EXPECT: zero adjustment + // TLDR: App is not set as a perceptible task and hence no oom_adj boosting. + mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.initialize(app, CACHED_APP_MIN_ADJ, + false, false, PROCESS_STATE_CACHED_ACTIVITY, + SCHED_GROUP_DEFAULT, 0, 0, PROCESS_STATE_IMPORTANT_FOREGROUND); + mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.onOtherActivity(-1); + assertEquals(CACHED_APP_MIN_ADJ, mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.adj); + + // GIVEN: perceptible adjustment is enabled (perceptible stop time is set) and + // elapsed time < PERCEPTIBLE_TASK_TIMEOUT + // EXPECT: adjustment to PERCEPTIBLE_MEDIUM_APP_ADJ + // TLDR: App is a perceptible task (e.g. opened from launcher) and has oom_adj boosting. + mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.initialize(app, CACHED_APP_MIN_ADJ, + false, false, PROCESS_STATE_CACHED_ACTIVITY, + SCHED_GROUP_DEFAULT, 0, 0, PROCESS_STATE_IMPORTANT_FOREGROUND); + mInjector.reset(); + mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.onOtherActivity(now); + assertEquals(PERCEPTIBLE_MEDIUM_APP_ADJ, + mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.adj); + + // GIVEN: perceptible adjustment is enabled (perceptible stop time is set) and + // elapsed time > PERCEPTIBLE_TASK_TIMEOUT + // EXPECT: adjustment to PREVIOUS_APP_ADJ + // TLDR: App is a perceptible task (e.g. opened from launcher) and has oom_adj boosting, but + // time has elapsed and has dropped to a lower boosting of PREVIOUS_APP_ADJ + mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.initialize(app, CACHED_APP_MIN_ADJ, + false, false, PROCESS_STATE_CACHED_ACTIVITY, + SCHED_GROUP_DEFAULT, 0, 0, PROCESS_STATE_IMPORTANT_FOREGROUND); + mInjector.jumpUptimeAheadTo(OomAdjuster.PERCEPTIBLE_TASK_TIMEOUT_MILLIS + 1000); + mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.onOtherActivity(0); + assertEquals(PREVIOUS_APP_ADJ, mService.mOomAdjuster.mTmpComputeOomAdjWindowCallback.adj); + } + + /** + * For Perceptible Tasks adjustment, this tests overall adjustment flow. + */ + @SuppressWarnings("GuardedBy") + @Test + @EnableFlags(Flags.FLAG_PERCEPTIBLE_TASKS) + public void testUpdateOomAdjPerceptible() { + ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, + MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); + WindowProcessController wpc = app.getWindowProcessController(); + + // Set uptime to be at least the timeout time + buffer, so that we don't end up with + // negative stopTime in our test input + mInjector.jumpUptimeAheadTo(OomAdjuster.PERCEPTIBLE_TASK_TIMEOUT_MILLIS + 60L * 1000L); + long now = mInjector.getUptimeMillis(); + doReturn(true).when(wpc).hasActivities(); + + // GIVEN: perceptible adjustment is is enabled + // EXPECT: perceptible-act adjustment + doReturn(WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) + .when(wpc).getActivityStateFlags(); + doReturn(now).when(wpc).getPerceptibleTaskStoppedTimeMillis(); + updateOomAdj(app); + assertProcStates(app, PROCESS_STATE_IMPORTANT_BACKGROUND, PERCEPTIBLE_MEDIUM_APP_ADJ, + SCHED_GROUP_BACKGROUND, "perceptible-act"); + + // GIVEN: perceptible adjustment is is enabled and timeout has been reached + // EXPECT: stale-perceptible-act adjustment + doReturn(WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) + .when(wpc).getActivityStateFlags(); + + doReturn(now - OomAdjuster.PERCEPTIBLE_TASK_TIMEOUT_MILLIS).when( + wpc).getPerceptibleTaskStoppedTimeMillis(); + updateOomAdj(app); + assertProcStates(app, PROCESS_STATE_LAST_ACTIVITY, PREVIOUS_APP_ADJ, + SCHED_GROUP_BACKGROUND, "stale-perceptible-act"); + + // GIVEN: perceptible adjustment is is disabled + // EXPECT: no perceptible adjustment + doReturn(WindowProcessController.ACTIVITY_STATE_FLAG_IS_STOPPING_FINISHING) + .when(wpc).getActivityStateFlags(); + doReturn(Long.MIN_VALUE).when(wpc).getPerceptibleTaskStoppedTimeMillis(); + updateOomAdj(app); + assertProcStates(app, PROCESS_STATE_CACHED_ACTIVITY, CACHED_APP_MIN_ADJ, + SCHED_GROUP_BACKGROUND, "cch-act"); + + // GIVEN: perceptible app is in foreground + // EXPECT: no perceptible adjustment + doReturn(WindowProcessController.ACTIVITY_STATE_FLAG_IS_VISIBLE) + .when(wpc).getActivityStateFlags(); + doReturn(now).when(wpc).getPerceptibleTaskStoppedTimeMillis(); + updateOomAdj(app); + assertProcStates(app, PROCESS_STATE_TOP, VISIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT, "vis-activity"); + } + @SuppressWarnings("GuardedBy") @Test public void testUpdateOomAdj_DoAll_Multiple_Provider_Retention() { diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp index 8eae9c7d71fa..e030b3f19e4f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp +++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp @@ -32,18 +32,18 @@ android_test { static_libs: [ "androidx.test.core", "androidx.test.runner", + "flag-junit", "mockito-target-extended-minus-junit4", "services.core", "truth", - "flag-junit", ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), { "true": ["service-crashrecovery-pre-jarjar"], default: [], }), libs: [ - "android.test.mock.stubs.system", "android.test.base.stubs.system", + "android.test.mock.stubs.system", "android.test.runner.stubs.system", ], @@ -55,7 +55,9 @@ android_test { certificate: "platform", platform_apis: true, test_suites: [ - "device-tests", "automotive-tests", + "device-tests", + "mts-crashrecovery", ], + min_sdk_version: "36", } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java index 904545bd3cc3..b4e845171a0b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobServiceContextTest.java @@ -276,6 +276,7 @@ public class JobServiceContextTest { final int jobId = 123; mJobServiceContext.setRunningJobLockedForTest(mMockJobStatus); mJobServiceContext.setRunningCallbackLockedForTest(mMockJobCallback); + mJobServiceContext.mVerb = JobServiceContext.VERB_EXECUTING; doReturn(jobId).when(mMockJobStatus).getJobId(); mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId); @@ -296,7 +297,25 @@ public class JobServiceContextTest { mJobServiceContext.setRunningCallbackLockedForTest(mMockJobCallback); mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId); + verify(mMockJobStatus, never()).setAbandoned(true); + + mJobServiceContext.setRunningJobLockedForTest(mMockJobStatus); + doReturn(jobId).when(mMockJobStatus).getJobId(); + + mJobServiceContext.mVerb = JobServiceContext.VERB_BINDING; + mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId); + verify(mMockJobStatus, never()).setAbandoned(true); + mJobServiceContext.mVerb = JobServiceContext.VERB_STARTING; + mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId); + verify(mMockJobStatus, never()).setAbandoned(true); + + mJobServiceContext.mVerb = JobServiceContext.VERB_STOPPING; + mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId); + verify(mMockJobStatus, never()).setAbandoned(true); + + mJobServiceContext.mVerb = JobServiceContext.VERB_FINISHED; + mJobServiceContext.doHandleAbandonedJob(mMockJobCallback, jobId); verify(mMockJobStatus, never()).setAbandoned(true); } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index c6870adb8464..4e4b3df3c935 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -295,15 +295,15 @@ public class QuotaControllerTest { } private void setCharging() { - doReturn(true).when(mJobSchedulerService).isBatteryCharging(); synchronized (mQuotaController.mLock) { + doReturn(true).when(mJobSchedulerService).isBatteryCharging(); mQuotaController.onBatteryStateChangedLocked(); } } private void setDischarging() { - doReturn(false).when(mJobSchedulerService).isBatteryCharging(); synchronized (mQuotaController.mLock) { + doReturn(false).when(mJobSchedulerService).isBatteryCharging(); mQuotaController.onBatteryStateChangedLocked(); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp index 5a802d9de2ff..36b064b9b090 100644 --- a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp +++ b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp @@ -30,18 +30,18 @@ android_test { static_libs: [ "androidx.test.runner", + "flag-junit", "mockito-target-extended-minus-junit4", "services.core", "truth", - "flag-junit", ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), { "true": ["service-crashrecovery-pre-jarjar"], default: [], }), libs: [ - "android.test.mock.stubs.system", "android.test.base.stubs.system", + "android.test.mock.stubs.system", "android.test.runner.stubs.system", ], @@ -53,9 +53,11 @@ android_test { certificate: "platform", platform_apis: true, test_suites: [ - "device-tests", "automotive-tests", + "device-tests", + "mts-crashrecovery", ], + min_sdk_version: "36", } test_module_config { diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java index 347dc81c6734..fb4d81ac831c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java @@ -43,7 +43,6 @@ import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; -import android.crashrecovery.flags.Flags; import android.os.Handler; import android.os.MessageQueue; import android.os.SystemProperties; @@ -273,7 +272,6 @@ public class RollbackPackageHealthObserverTest { @Test public void healthCheckFailed_impactLevelLow_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, @@ -304,7 +302,6 @@ public class RollbackPackageHealthObserverTest { @Test public void healthCheckFailed_impactLevelHigh_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, @@ -335,7 +332,6 @@ public class RollbackPackageHealthObserverTest { @Test public void healthCheckFailed_impactLevelManualOnly_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, @@ -365,7 +361,6 @@ public class RollbackPackageHealthObserverTest { @Test public void healthCheckFailed_impactLevelLowAndHigh_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, @@ -404,7 +399,6 @@ public class RollbackPackageHealthObserverTest { @Test public void execute_impactLevelLow_nativeCrash_rollback() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId = 1; VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -438,7 +432,6 @@ public class RollbackPackageHealthObserverTest { @Test public void execute_impactLevelLow_rollbackFailedPackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId1 = 1; VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -483,7 +476,6 @@ public class RollbackPackageHealthObserverTest { @Test public void execute_impactLevelLow_rollbackAll() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId1 = 1; VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -530,7 +522,6 @@ public class RollbackPackageHealthObserverTest { @Test public void execute_impactLevelLowAndHigh_rollbackLow() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId1 = 1; VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -578,7 +569,6 @@ public class RollbackPackageHealthObserverTest { @Test public void execute_impactLevelHigh_rollbackHigh() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId2 = 2; VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2); VersionedPackage appBTo = new VersionedPackage(APP_B, VERSION_CODE); @@ -612,7 +602,6 @@ public class RollbackPackageHealthObserverTest { */ @Test public void onBootLoop_impactLevelLow_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, @@ -637,7 +626,6 @@ public class RollbackPackageHealthObserverTest { @Test public void onBootLoop_impactLevelHigh_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, @@ -662,7 +650,6 @@ public class RollbackPackageHealthObserverTest { @Test public void onBootLoop_impactLevelHighDisableHighImpactRollback_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true)); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -692,7 +679,6 @@ public class RollbackPackageHealthObserverTest { @Test public void onBootLoop_impactLevelManualOnly_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, @@ -720,7 +706,6 @@ public class RollbackPackageHealthObserverTest { @Test public void onBootLoop_impactLevelLowAndHigh_onePackage() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, @@ -757,7 +742,6 @@ public class RollbackPackageHealthObserverTest { @Test public void executeBootLoopMitigation_impactLevelLow_rollbackAll() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId1 = 1; VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -802,7 +786,6 @@ public class RollbackPackageHealthObserverTest { @Test public void executeBootLoopMitigation_impactLevelLowAndHigh_rollbackLow() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId1 = 1; VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -847,7 +830,6 @@ public class RollbackPackageHealthObserverTest { @Test public void executeBootLoopMitigation_impactLevelHigh_rollbackHigh() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId2 = 2; VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2); VersionedPackage appBTo = new VersionedPackage(APP_B, VERSION_CODE); @@ -882,7 +864,6 @@ public class RollbackPackageHealthObserverTest { @Test public void execute_impactLevelLowAndManual_rollbackLowImpactOnly() throws PackageManager.NameNotFoundException, InterruptedException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId1 = 1; VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -928,7 +909,6 @@ public class RollbackPackageHealthObserverTest { @Test public void execute_impactLevelManual_rollbackLowImpactOnly() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId1 = 1; VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); @@ -962,7 +942,6 @@ public class RollbackPackageHealthObserverTest { @Test public void executeBootLoopMitigation_impactLevelHighMultiplePackage_rollbackHigh() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); int rollbackId1 = 1; VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2); VersionedPackage appBTo = new VersionedPackage(APP_B, VERSION_CODE); @@ -1008,7 +987,6 @@ public class RollbackPackageHealthObserverTest { @Test public void executeBootLoopMitigation_impactLevelHighKillSwitchTrue_rollbackHigh() throws PackageManager.NameNotFoundException { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true)); int rollbackId1 = 1; VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java index 8fc8c9f677a6..6be9c6d4b80c 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderPerfTest.java @@ -48,6 +48,7 @@ import org.junit.runner.RunWith; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; @@ -121,7 +122,7 @@ public class BatteryUsageStatsProviderPerfTest { } @Test - public void getBatteryUsageStats_accumulated() { + public void getBatteryUsageStats_accumulated() throws IOException { BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder() .setMaxStatsAgeMs(0) .includePowerStateData() @@ -155,6 +156,8 @@ public class BatteryUsageStatsProviderPerfTest { // Verify that all iterations produce the same result assertThat(cpuConsumedPower).isEqualTo(expectedCpuPower); } + stats.close(); + state.resumeTiming(); } } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java index cb9d9b12a2fc..dcddf06f01fb 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/CpuPowerStatsProcessorTest.java @@ -34,6 +34,7 @@ import static org.junit.Assert.fail; import android.os.BatteryConsumer; import android.os.PersistableBundle; import android.platform.test.ravenwood.RavenwoodRule; +import android.util.IntArray; import android.util.LongArray; import androidx.test.filters.SmallTest; @@ -51,7 +52,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -315,8 +315,12 @@ public class CpuPowerStatsProcessorTest { } @Override - void collectUids(Collection<Integer> uids) { - uids.addAll(mUids); + IntArray getActiveUids() { + IntArray uids = new IntArray(); + for (Integer uid : mUids) { + uids.add(uid); + } + return uids; } void verifyPowerEstimates() { diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java index a232c0c7aec9..3b614bdb38ed 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/MultiStateStatsTest.java @@ -143,6 +143,8 @@ public class MultiStateStatsTest { multiStateStats.increment(new long[]{200, 200}, 5000); + multiStateStats.increment(null, 6000); // No-op + long[] stats = new long[DIMENSION_COUNT]; multiStateStats.getStats(stats, new int[]{0, BatteryConsumer.PROCESS_STATE_FOREGROUND, 0}); // (400 - 100) * 0.5 + (600 - 400) * 0.5 diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml index 834fea46e505..4531b3948495 100644 --- a/services/tests/servicestests/AndroidManifest.xml +++ b/services/tests/servicestests/AndroidManifest.xml @@ -199,6 +199,10 @@ <service android:name="com.android.server.job.MockBiasJobService" android:permission="android.permission.BIND_JOB_SERVICE"/> + <activity + android:name="android.app.Activity" + android:exported="false" /> + <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity"/> <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2"/> <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3"/> diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java index 8dfd54fe38bc..42b84bdc51e6 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java @@ -46,12 +46,11 @@ import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityActi import static android.view.accessibility.AccessibilityNodeInfo.FOCUS_INPUT; import static android.view.accessibility.AccessibilityNodeInfo.ROOT_NODE_ID; -import static org.hamcrest.Matchers.hasItems; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -65,6 +64,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityService; @@ -90,14 +90,20 @@ import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.test.FakePermissionEnforcer; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.util.Pair; import android.view.Display; import android.view.KeyEvent; import android.view.MagnificationSpec; +import android.view.SurfaceControl; +import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; import android.view.accessibility.IAccessibilityInteractionConnectionCallback; +import android.view.accessibility.IWindowSurfaceInfoCallback; +import android.window.ScreenCapture; import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection; import com.android.server.accessibility.magnification.MagnificationProcessor; @@ -105,6 +111,7 @@ import com.android.server.accessibility.test.MessageCapturingHandler; import com.android.server.wm.WindowManagerInternal; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -121,6 +128,10 @@ import java.util.concurrent.Callable; * Tests for the AbstractAccessibilityServiceConnection */ public class AbstractAccessibilityServiceConnectionTest { + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private static final ComponentName COMPONENT_NAME = new ComponentName( "com.android.server.accessibility", ".AbstractAccessibilityServiceConnectionTest"); private static final String PACKAGE_NAME1 = "com.android.server.accessibility1"; @@ -264,7 +275,7 @@ public class AbstractAccessibilityServiceConnectionTest { @Test public void getCapabilities() { - assertThat(mServiceConnection.getCapabilities(), is(A11Y_SERVICE_CAPABILITY)); + assertThat(mServiceConnection.getCapabilities()).isEqualTo(A11Y_SERVICE_CAPABILITY); } @Test @@ -329,7 +340,7 @@ public class AbstractAccessibilityServiceConnectionTest { 0, null, 0); mServiceConnection.setServiceInfo(serviceInfo); - assertThat(mServiceConnection.canReceiveEventsLocked(), is(true)); + assertThat(mServiceConnection.canReceiveEventsLocked()).isTrue(); } @Test @@ -348,9 +359,11 @@ public class AbstractAccessibilityServiceConnectionTest { mServiceConnection.getWindows(); assertEquals(2, allWindows.size()); - assertThat(allWindows.get(Display.DEFAULT_DISPLAY), is(mA11yWindowInfos)); + assertThat(allWindows.get(Display.DEFAULT_DISPLAY)) + .containsExactlyElementsIn(mA11yWindowInfos); assertEquals(2, allWindows.get(Display.DEFAULT_DISPLAY).size()); - assertThat(allWindows.get(SECONDARY_DISPLAY_ID), is(mA11yWindowInfosOnSecondDisplay)); + assertThat(allWindows.get(SECONDARY_DISPLAY_ID)) + .containsExactlyElementsIn(mA11yWindowInfosOnSecondDisplay); assertEquals(1, allWindows.get(SECONDARY_DISPLAY_ID).size()); } @@ -358,12 +371,12 @@ public class AbstractAccessibilityServiceConnectionTest { public void getWindows_returnNull() { // no canRetrieveWindows, should return null when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(false); - assertThat(mServiceConnection.getWindows(), is(nullValue())); + assertThat(mServiceConnection.getWindows()).isNull(); // no checkAccessibilityAccess, should return null when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(true); when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false); - assertThat(mServiceConnection.getWindows(), is(nullValue())); + assertThat(mServiceConnection.getWindows()).isNull(); } @Test @@ -378,19 +391,19 @@ public class AbstractAccessibilityServiceConnectionTest { @Test public void getWindow() { - assertThat(mServiceConnection.getWindow(WINDOWID), is(mA11yWindowInfos.get(0))); + assertThat(mServiceConnection.getWindow(WINDOWID)).isEqualTo(mA11yWindowInfos.get(0)); } @Test public void getWindow_returnNull() { // no canRetrieveWindows, should return null when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(false); - assertThat(mServiceConnection.getWindow(WINDOWID), is(nullValue())); + assertThat(mServiceConnection.getWindow(WINDOWID)).isNull(); // no checkAccessibilityAccess, should return null when(mMockSecurityPolicy.canRetrieveWindowsLocked(mServiceConnection)).thenReturn(true); when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false); - assertThat(mServiceConnection.getWindow(WINDOWID), is(nullValue())); + assertThat(mServiceConnection.getWindow(WINDOWID)).isNull(); } @Test @@ -405,8 +418,8 @@ public class AbstractAccessibilityServiceConnectionTest { @Test public void getWindow_onNonDefaultDisplay() { - assertThat(mServiceConnection.getWindow(WINDOWID_ONSECONDDISPLAY), - is(mA11yWindowInfosOnSecondDisplay.get(0))); + assertThat(mServiceConnection.getWindow(WINDOWID_ONSECONDDISPLAY)) + .isEqualTo(mA11yWindowInfosOnSecondDisplay.get(0)); } @Test @@ -415,9 +428,9 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockSecurityPolicy.canGetAccessibilityNodeInfoLocked( USER_ID, mServiceConnection, WINDOWID)).thenReturn(false); for (int i = 0; i < mFindA11yNodesFunctions.length; i++) { - assertThat(mFindA11yNodesFunctions[i].call(), is(nullValue())); + assertThat(mFindA11yNodesFunctions[i].call()).isNull(); } - assertThat(mPerformA11yAction.call(), is(false)); + assertThat(mPerformA11yAction.call()).isFalse(); verifyNoMoreInteractions(mMockIA11yInteractionConnection); verify(mMockSecurityPolicy, never()).computeValidReportedPackages(any(), anyInt()); @@ -428,9 +441,9 @@ public class AbstractAccessibilityServiceConnectionTest { throws Exception { when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(false); for (int i = 0; i < mFindA11yNodesFunctions.length; i++) { - assertThat(mFindA11yNodesFunctions[i].call(), is(nullValue())); + assertThat(mFindA11yNodesFunctions[i].call()).isNull(); } - assertThat(mPerformA11yAction.call(), is(false)); + assertThat(mPerformA11yAction.call()).isFalse(); verifyNoMoreInteractions(mMockIA11yInteractionConnection); verify(mMockSecurityPolicy, never()).computeValidReportedPackages(any(), anyInt()); @@ -441,9 +454,9 @@ public class AbstractAccessibilityServiceConnectionTest { throws Exception { when(mMockA11yWindowManager.getConnectionLocked(USER_ID, WINDOWID)).thenReturn(null); for (int i = 0; i < mFindA11yNodesFunctions.length; i++) { - assertThat(mFindA11yNodesFunctions[i].call(), is(nullValue())); + assertThat(mFindA11yNodesFunctions[i].call()).isNull(); } - assertThat(mPerformA11yAction.call(), is(false)); + assertThat(mPerformA11yAction.call()).isFalse(); verifyNoMoreInteractions(mMockIA11yInteractionConnection); verify(mMockSecurityPolicy, never()).computeValidReportedPackages(any(), anyInt()); @@ -562,7 +575,7 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockFingerprintGestureDispatcher.isFingerprintGestureDetectionAvailable()) .thenReturn(true); final boolean result = mServiceConnection.isFingerprintGestureDetectionAvailable(); - assertThat(result, is(true)); + assertThat(result).isTrue(); } @Test @@ -573,14 +586,14 @@ public class AbstractAccessibilityServiceConnectionTest { // Return false if device does not support fingerprint when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(false); boolean result = mServiceConnection.isFingerprintGestureDetectionAvailable(); - assertThat(result, is(false)); + assertThat(result).isFalse(); // Return false if service does not have flag when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true); mSpyServiceInfo.flags = A11Y_SERVICE_FLAG & ~FLAG_REQUEST_FINGERPRINT_GESTURES; mServiceConnection.setServiceInfo(mSpyServiceInfo); result = mServiceConnection.isFingerprintGestureDetectionAvailable(); - assertThat(result, is(false)); + assertThat(result).isFalse(); } @Test @@ -590,7 +603,7 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockMagnificationProcessor.getScale(displayId)).thenReturn(scale); final float result = mServiceConnection.getMagnificationScale(displayId); - assertThat(result, is(scale)); + assertThat(result).isEqualTo(scale); } @Test @@ -601,7 +614,7 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); final float result = mServiceConnection.getMagnificationScale(displayId); - assertThat(result, is(1.0f)); + assertThat(result).isEqualTo(1.0f); } @Test @@ -616,7 +629,7 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); final Region result = mServiceConnection.getMagnificationRegion(displayId); - assertThat(result.isEmpty(), is(true)); + assertWithMessage("Non-empty region: " + result).that(result.isEmpty()).isTrue(); } @Test @@ -642,7 +655,7 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); final float result = mServiceConnection.getMagnificationCenterX(displayId); - assertThat(result, is(0.0f)); + assertThat(result).isEqualTo(0.0f); } @Test @@ -654,7 +667,7 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); final float result = mServiceConnection.getMagnificationCenterY(displayId); - assertThat(result, is(0.0f)); + assertThat(result).isEqualTo(0.0f); } @Test @@ -664,7 +677,7 @@ public class AbstractAccessibilityServiceConnectionTest { true); final boolean result = mServiceConnection.resetMagnification(displayId, true); - assertThat(result, is(true)); + assertThat(result).isTrue(); } @Test @@ -675,7 +688,7 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockSecurityPolicy.canControlMagnification(mServiceConnection)).thenReturn(false); final boolean result = mServiceConnection.resetMagnification(displayId, true); - assertThat(result, is(false)); + assertThat(result).isFalse(); } @Test @@ -686,7 +699,7 @@ public class AbstractAccessibilityServiceConnectionTest { when(mMockSystemSupport.getCurrentUserIdLocked()).thenReturn(USER_ID2); final boolean result = mServiceConnection.resetMagnification(displayId, true); - assertThat(result, is(false)); + assertThat(result).isFalse(); } @Test @@ -765,6 +778,134 @@ public class AbstractAccessibilityServiceConnectionTest { == bundle.getInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS))); } + private void setPreinstalledA11yTool(boolean isPreinstalledA11yTool) { + when(mSpyServiceInfo.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) + .thenReturn(isPreinstalledA11yTool); + when(mSpyServiceInfo.isAccessibilityTool()).thenReturn(isPreinstalledA11yTool); + } + + @Test + @EnableFlags(Flags.FLAG_ALLOW_SECURE_SCREENSHOTS) + public void takeScreenshot_standardService_cannotCaptureSecureLayers() { + setPreinstalledA11yTool(false); + + takeScreenshotOfDisplay(); + + final ArgumentCaptor<ScreenCapture.CaptureArgs> displayArgsCaptor = + ArgumentCaptor.forClass(ScreenCapture.CaptureArgs.class); + verify(mMockWindowManagerInternal).captureDisplay( + eq(Display.DEFAULT_DISPLAY), displayArgsCaptor.capture(), any()); + assertThat(displayArgsCaptor.getValue().mCaptureSecureLayers).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ALLOW_SECURE_SCREENSHOTS) + public void takeScreenshot_preinstalledA11yTool_canCaptureSecureLayers() { + setPreinstalledA11yTool(true); + + takeScreenshotOfDisplay(); + + final ArgumentCaptor<ScreenCapture.CaptureArgs> displayArgsCaptor = + ArgumentCaptor.forClass(ScreenCapture.CaptureArgs.class); + verify(mMockWindowManagerInternal).captureDisplay( + anyInt(), displayArgsCaptor.capture(), any()); + assertThat(displayArgsCaptor.getValue().mCaptureSecureLayers).isTrue(); + } + + private void takeScreenshotOfDisplay() { + when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(true); + when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(true); + + final DisplayManager displayManager = new DisplayManager(mMockContext); + when(mMockContext.getSystemService(Context.DISPLAY_SERVICE)).thenReturn(displayManager); + + mServiceConnection.takeScreenshot(Display.DEFAULT_DISPLAY, + new RemoteCallback(mMockListener)); + } + + @Test + @EnableFlags(Flags.FLAG_ALLOW_SECURE_SCREENSHOTS) + public void takeScreenshotOfWindow_standardWindow_standardService_cannotCaptureSecureLayers() + throws Exception { + setPreinstalledA11yTool(false); + + takeScreenshotOfWindow(/*windowFlags=*/0); + + // Screenshot was allowed + final ArgumentCaptor<ScreenCapture.LayerCaptureArgs> layerArgsCaptor = + ArgumentCaptor.forClass(ScreenCapture.LayerCaptureArgs.class); + verify(mMockSystemSupport).performScreenCapture(layerArgsCaptor.capture(), any()); + // ...without secure layers included + assertThat(layerArgsCaptor.getValue().mCaptureSecureLayers).isFalse(); + // No error sent to callback + verifyZeroInteractions(mMockCallback); + } + + @Test + @EnableFlags(Flags.FLAG_ALLOW_SECURE_SCREENSHOTS) + public void takeScreenshotOfWindow_standardWindow_preinstalledA11yTool_canCaptureSecureLayers() + throws Exception { + setPreinstalledA11yTool(true); + + takeScreenshotOfWindow(/*windowFlags=*/0); + + // Screenshot was allowed + final ArgumentCaptor<ScreenCapture.LayerCaptureArgs> layerArgsCaptor = + ArgumentCaptor.forClass(ScreenCapture.LayerCaptureArgs.class); + verify(mMockSystemSupport).performScreenCapture(layerArgsCaptor.capture(), any()); + // ...with secure layers included + assertThat(layerArgsCaptor.getValue().mCaptureSecureLayers).isTrue(); + // No error sent to callback + verifyZeroInteractions(mMockCallback); + } + + @Test + @EnableFlags(Flags.FLAG_ALLOW_SECURE_SCREENSHOTS) + public void takeScreenshotOfWindow_secureWindow_standardService_sendsCallbackError() + throws Exception { + setPreinstalledA11yTool(false); + + takeScreenshotOfWindow(WindowManager.LayoutParams.FLAG_SECURE); + + // Screenshot was not allowed + verify(mMockSystemSupport, never()).performScreenCapture(any(), any()); + // Error sent to callback + verify(mMockCallback).sendTakeScreenshotOfWindowError( + AccessibilityService.ERROR_TAKE_SCREENSHOT_SECURE_WINDOW, INTERACTION_ID); + } + + @Test + @EnableFlags(Flags.FLAG_ALLOW_SECURE_SCREENSHOTS) + public void takeScreenshotOfWindow_secureWindow_preinstalledA11yTool_canCaptureSecureLayers() + throws Exception { + setPreinstalledA11yTool(true); + + takeScreenshotOfWindow(WindowManager.LayoutParams.FLAG_SECURE); + + // Screenshot was allowed + final ArgumentCaptor<ScreenCapture.LayerCaptureArgs> layerArgsCaptor = + ArgumentCaptor.forClass(ScreenCapture.LayerCaptureArgs.class); + verify(mMockSystemSupport).performScreenCapture(layerArgsCaptor.capture(), any()); + // ...with secure layers included + assertThat(layerArgsCaptor.getValue().mCaptureSecureLayers).isTrue(); + // No error sent to callback + verifyZeroInteractions(mMockCallback); + } + + private void takeScreenshotOfWindow(int windowFlags) throws Exception { + when(mMockSecurityPolicy.canTakeScreenshotLocked(mServiceConnection)).thenReturn(true); + when(mMockSecurityPolicy.checkAccessibilityAccess(mServiceConnection)).thenReturn(true); + + mServiceConnection.takeScreenshotOfWindow( + WINDOWID, INTERACTION_ID, /*listener=*/null, mMockCallback); + final ArgumentCaptor<IWindowSurfaceInfoCallback> windowSurfaceCallbackCaptor = + ArgumentCaptor.forClass(IWindowSurfaceInfoCallback.class); + verify(mMockIA11yInteractionConnection).getWindowSurfaceInfo( + windowSurfaceCallbackCaptor.capture()); + windowSurfaceCallbackCaptor.getValue().provideWindowSurfaceInfo( + windowFlags, /*appUid=*/0, new SurfaceControl()); + } + private void updateServiceInfo(AccessibilityServiceInfo serviceInfo, int eventType, int feedbackType, int flags, String[] packageNames, int notificationTimeout) { serviceInfo.eventTypes = eventType; @@ -837,8 +978,8 @@ public class AbstractAccessibilityServiceConnectionTest { ArgumentCaptor.forClass(AccessibilityNodeInfo.class); verify(mMockCallback).setFindAccessibilityNodeInfoResult(captor.capture(), eq(INTERACTION_ID)); - assertThat(captor.getValue().getActionList(), - hasItems(AccessibilityAction.ACTION_CLICK, AccessibilityAction.ACTION_EXPAND)); + assertThat(captor.getValue().getActionList()).containsAtLeast( + AccessibilityAction.ACTION_CLICK, AccessibilityAction.ACTION_EXPAND); } private static class TestAccessibilityServiceConnection diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java index 7f60caaa569b..0745c68fd337 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickControllerTest.java @@ -25,6 +25,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Context; import android.platform.test.annotations.DisableFlags; @@ -400,6 +401,46 @@ public class AutoclickControllerTest { .isNotEqualTo(initialScheduledTime); } + @Test + @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_AUTOCLICK_INDICATOR) + public void pauseButton_flagOn_clickNotTriggeredWhenPaused() { + injectFakeMouseActionHoverMoveEvent(); + + // Pause autoclick. + AutoclickTypePanel mockAutoclickTypePanel = mock(AutoclickTypePanel.class); + when(mockAutoclickTypePanel.isPaused()).thenReturn(true); + mController.mAutoclickTypePanel = mockAutoclickTypePanel; + + // Send hover move event. + MotionEvent hoverMove = MotionEvent.obtain( + /* downTime= */ 0, + /* eventTime= */ 100, + /* action= */ MotionEvent.ACTION_HOVER_MOVE, + /* x= */ 30f, + /* y= */ 0f, + /* metaState= */ 0); + hoverMove.setSource(InputDevice.SOURCE_MOUSE); + mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0); + + // Verify there is not a pending click. + assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse(); + assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1); + + // Resume autoclick. + when(mockAutoclickTypePanel.isPaused()).thenReturn(false); + + // Send initial move event again. Because this is the first recorded move, a click won't be + // scheduled. + injectFakeMouseActionHoverMoveEvent(); + assertThat(mController.mClickScheduler.getIsActiveForTesting()).isFalse(); + assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isEqualTo(-1); + + // Send move again to trigger click and verify there is now a pending click. + mController.onMotionEvent(hoverMove, hoverMove, /* policyFlags= */ 0); + assertThat(mController.mClickScheduler.getIsActiveForTesting()).isTrue(); + assertThat(mController.mClickScheduler.getScheduledClickTimeForTesting()).isNotEqualTo(-1); + } + private void injectFakeMouseActionHoverMoveEvent() { MotionEvent event = getFakeMotionHoverMoveEvent(); event.setSource(InputDevice.SOURCE_MOUSE); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java index 00cc7264c1d0..ba672dcd299b 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java @@ -30,6 +30,7 @@ import android.graphics.drawable.GradientDrawable; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; +import android.view.Gravity; import android.view.View; import android.view.WindowManager; import android.widget.LinearLayout; @@ -63,8 +64,11 @@ public class AutoclickTypePanelTest { private LinearLayout mDoubleClickButton; private LinearLayout mDragButton; private LinearLayout mScrollButton; + private LinearLayout mPauseButton; + private LinearLayout mPositionButton; private @AutoclickType int mActiveClickType = AUTOCLICK_TYPE_LEFT_CLICK; + private boolean mPaused; private final ClickPanelControllerInterface clickPanelController = new ClickPanelControllerInterface() { @@ -74,7 +78,9 @@ public class AutoclickTypePanelTest { } @Override - public void toggleAutoclickPause() {} + public void toggleAutoclickPause(boolean paused) { + mPaused = paused; + } }; @Before @@ -91,6 +97,8 @@ public class AutoclickTypePanelTest { contentView.findViewById(R.id.accessibility_autoclick_double_click_layout); mScrollButton = contentView.findViewById(R.id.accessibility_autoclick_scroll_layout); mDragButton = contentView.findViewById(R.id.accessibility_autoclick_drag_layout); + mPauseButton = contentView.findViewById(R.id.accessibility_autoclick_pause_layout); + mPositionButton = contentView.findViewById(R.id.accessibility_autoclick_position_layout); } @Test @@ -106,6 +114,7 @@ public class AutoclickTypePanelTest { assertThat(mDoubleClickButton.getVisibility()).isEqualTo(View.GONE); assertThat(mDragButton.getVisibility()).isEqualTo(View.GONE); assertThat(mScrollButton.getVisibility()).isEqualTo(View.GONE); + assertThat(mPauseButton.getVisibility()).isEqualTo(View.VISIBLE); } @Test @@ -124,6 +133,9 @@ public class AutoclickTypePanelTest { assertThat(mDoubleClickButton.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mDragButton.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mScrollButton.getVisibility()).isEqualTo(View.VISIBLE); + + // Pause button is always visible. + assertThat(mPauseButton.getVisibility()).isEqualTo(View.VISIBLE); } @Test @@ -142,6 +154,9 @@ public class AutoclickTypePanelTest { assertThat(mLeftClickButton.getVisibility()).isEqualTo(View.GONE); assertThat(mDoubleClickButton.getVisibility()).isEqualTo(View.GONE); assertThat(mDragButton.getVisibility()).isEqualTo(View.GONE); + + // Pause button is always visible. + assertThat(mPauseButton.getVisibility()).isEqualTo(View.VISIBLE); } @Test @@ -166,9 +181,50 @@ public class AutoclickTypePanelTest { assertThat(mActiveClickType).isEqualTo(AUTOCLICK_TYPE_SCROLL); } + @Test + public void moveToNextCorner_positionButton_rotatesThroughAllPositions() { + // Define all positions in sequence + int[][] expectedPositions = { + {0, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90}, + {1, Gravity.START | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90}, + {2, Gravity.START | Gravity.TOP, /*x=*/ 15, /*y=*/ 30}, + {3, Gravity.END | Gravity.TOP, /*x=*/ 15, /*y=*/ 30}, + {0, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90} + }; + + // Check initial position + verifyPanelPosition(expectedPositions[0]); + + // Move through all corners. + for (int i = 1; i < expectedPositions.length; i++) { + mPositionButton.callOnClick(); + verifyPanelPosition(expectedPositions[i]); + } + } + + @Test + public void pauseButton_onClick() { + mPauseButton.callOnClick(); + assertThat(mPaused).isTrue(); + assertThat(mAutoclickTypePanel.isPaused()).isTrue(); + + mPauseButton.callOnClick(); + assertThat(mPaused).isFalse(); + assertThat(mAutoclickTypePanel.isPaused()).isFalse(); + } + private void verifyButtonHasSelectedStyle(@NonNull LinearLayout button) { GradientDrawable gradientDrawable = (GradientDrawable) button.getBackground(); assertThat(gradientDrawable.getColor().getDefaultColor()) .isEqualTo(mTestableContext.getColor(R.color.materialColorPrimary)); } + + private void verifyPanelPosition(int[] expectedPosition) { + WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParams(); + assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()).isEqualTo( + expectedPosition[0]); + assertThat(params.gravity).isEqualTo(expectedPosition[1]); + assertThat(params.x).isEqualTo(expectedPosition[2]); + assertThat(params.y).isEqualTo(expectedPosition[3]); + } } diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java index b5a538fa09f8..c7da27420cbb 100644 --- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceInventoryTest.java @@ -103,7 +103,7 @@ public class AudioDeviceInventoryTest { // NOTE: for now this is only when flag asDeviceConnectionFailure is true if (asDeviceConnectionFailure()) { when(mSpyAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_AVAILABLE, - AudioSystem.AUDIO_FORMAT_DEFAULT)) + AudioSystem.AUDIO_FORMAT_DEFAULT, false /*deviceSwitch*/)) .thenReturn(AudioSystem.AUDIO_STATUS_ERROR); runWithBluetoothPrivilegedPermission( () -> mDevInventory.onSetBtActiveDevice(/*btInfo*/ btInfo, @@ -115,7 +115,7 @@ public class AudioDeviceInventoryTest { // test that the device is added when AudioSystem returns AUDIO_STATUS_OK // when setDeviceConnectionState is called for the connection when(mSpyAudioSystem.setDeviceConnectionState(ada, AudioSystem.DEVICE_STATE_AVAILABLE, - AudioSystem.AUDIO_FORMAT_DEFAULT)) + AudioSystem.AUDIO_FORMAT_DEFAULT, false /*deviceSwitch*/)) .thenReturn(AudioSystem.AUDIO_STATUS_OK); runWithBluetoothPrivilegedPermission( () -> mDevInventory.onSetBtActiveDevice(/*btInfo*/ btInfo, diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java index ce59a86c6ca3..39e7d727f7c5 100644 --- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java +++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java @@ -51,9 +51,9 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter { // Overrides of AudioSystemAdapter @Override public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state, - int codecFormat) { - Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, 0x%s", - attributes.toString(), state, Integer.toHexString(codecFormat))); + int codecFormat, boolean deviceSwitch) { + Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, 0x%s %b", + attributes.toString(), state, Integer.toHexString(codecFormat), deviceSwitch)); return AudioSystem.AUDIO_STATUS_OK; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index e0023e59af50..30aa8cebdff6 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1768,7 +1768,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test - @Ignore // b/396073342 public void testCertificateDisclosure() throws Exception { final int userId = CALLER_USER_HANDLE; final UserHandle user = UserHandle.of(userId); @@ -4613,7 +4612,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test - @Ignore // b/396073342 public void testGetLastBugReportRequestTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -4661,7 +4659,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test - @Ignore // b/396073342 public void testGetLastNetworkLogRetrievalTime() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); @@ -6444,7 +6441,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test - @Ignore // b/396073342 public void testGetOwnerInstalledCaCertsForDeviceOwner() throws Exception { mServiceContext.packageName = mRealTestContext.getPackageName(); mServiceContext.applicationInfo = new ApplicationInfo(); @@ -6456,7 +6452,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test - @Ignore // b/396073342 public void testGetOwnerInstalledCaCertsForProfileOwner() throws Exception { mServiceContext.packageName = mRealTestContext.getPackageName(); mServiceContext.applicationInfo = new ApplicationInfo(); @@ -6469,7 +6464,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test - @Ignore // b/396073342 public void testGetOwnerInstalledCaCertsForDelegate() throws Exception { mServiceContext.packageName = mRealTestContext.getPackageName(); mServiceContext.applicationInfo = new ApplicationInfo(); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index e5fac7ac5e0c..00b0c558b4e3 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -263,6 +263,11 @@ public class DpmMockContext extends MockContext { } @Override + public Context getApplicationContext() { + return this; + } + + @Override public PackageManager getPackageManager() { return mMockSystemServices.packageManager; } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java index fca0cfbc7d2f..b2d48a77386f 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseAbsoluteVolumeBehaviorTest.java @@ -16,6 +16,7 @@ package com.android.server.hdmi; +import static android.content.pm.PackageManager.FEATURE_HDMI_CEC; import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM; import static com.android.server.hdmi.HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP; @@ -25,6 +26,7 @@ import static com.android.server.hdmi.HdmiCecFeatureAction.DELAY_GIVE_AUDIO_STAT import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.TruthJUnit.assume; +import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -122,6 +124,9 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { @Before public void setUp() throws RemoteException { + assumeTrue("Test requires FEATURE_HDMI_CEC", + InstrumentationRegistry.getTargetContext().getPackageManager() + .hasSystemFeature(FEATURE_HDMI_CEC)); MockitoAnnotations.initMocks(this); mContextSpy = spy(new ContextWrapper( @@ -432,7 +437,7 @@ public abstract class BaseAbsoluteVolumeBehaviorTest { .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) .setMinVolumeIndex(AudioStatus.MIN_VOLUME) .build()), - any(), any(), anyBoolean()); + anyBoolean(), any(), any()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java index ec44a918f8e8..f44517a47f55 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/BaseTvToAudioSystemAvbTest.java @@ -112,7 +112,7 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) .setMinVolumeIndex(AudioStatus.MIN_VOLUME) .build()), - any(), any(), anyBoolean()); + anyBoolean(), any(), any()); } @@ -135,7 +135,7 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) .setMinVolumeIndex(AudioStatus.MIN_VOLUME) .build()), - any(), any(), anyBoolean()); + anyBoolean(), any(), any()); } @Test @@ -160,7 +160,7 @@ public abstract class BaseTvToAudioSystemAvbTest extends BaseAbsoluteVolumeBehav .setMaxVolumeIndex(AudioStatus.MAX_VOLUME) .setMinVolumeIndex(AudioStatus.MIN_VOLUME) .build()), - any(), any(), anyBoolean()); + anyBoolean(), any(), any()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java index 7294ba62cdae..90f94cb4b596 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeAudioFramework.java @@ -183,9 +183,9 @@ public class FakeAudioFramework { public void setDeviceAbsoluteVolumeBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { + @NonNull OnAudioDeviceVolumeChangedListener vclistener) { setVolumeBehaviorHelper(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE); } @@ -193,9 +193,9 @@ public class FakeAudioFramework { public void setDeviceAbsoluteVolumeAdjustOnlyBehavior( @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo volume, + boolean handlesVolumeAdjustment, @NonNull @CallbackExecutor Executor executor, - @NonNull OnAudioDeviceVolumeChangedListener vclistener, - boolean handlesVolumeAdjustment) { + @NonNull OnAudioDeviceVolumeChangedListener vclistener) { setVolumeBehaviorHelper(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index 87c9db2fe565..acbce36c3d7f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -354,14 +354,20 @@ public abstract class BaseLockSettingsServiceTests { @After public void tearDown_baseServices() throws Exception { - mStorage.closeDatabase(); + if (mStorage != null) { + mStorage.closeDatabase(); + } File db = InstrumentationRegistry.getContext().getDatabasePath("locksettings.db"); assertTrue(!db.exists() || db.delete()); - File storageDir = mStorage.mStorageDir; - assertTrue(FileUtils.deleteContents(storageDir)); + if (mStorage != null) { + File storageDir = mStorage.mStorageDir; + assertTrue(FileUtils.deleteContents(storageDir)); + } - mPasswordSlotManager.cleanup(); + if (mPasswordSlotManager != null) { + mPasswordSlotManager.cleanup(); + } } protected void flushHandlerTasks() { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java index 02b86db6ab6f..387b89a41eba 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java @@ -124,7 +124,9 @@ public class LockSettingsStorageTests { @After public void tearDown() throws Exception { - mStorage.closeDatabase(); + if (mStorage != null) { + mStorage.closeDatabase(); + } } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java index 2faf6a2b29d1..2c2b9374fdf9 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java @@ -49,7 +49,9 @@ public class PasswordSlotManagerTests { @After public void tearDown() throws Exception { - mManager.cleanup(); + if (mManager != null) { + mManager.cleanup(); + } } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 1514de04fb08..5add74e5b69e 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -156,9 +156,12 @@ public class KeySyncTaskTest { @After public void tearDown() { - mRecoverableKeyStoreDb.close(); - mDatabaseFile.delete(); - + if (mRecoverableKeyStoreDb != null) { + mRecoverableKeyStoreDb.close(); + } + if (mDatabaseFile != null) { + mDatabaseFile.delete(); + } File file = new File(InstrumentationRegistry.getTargetContext().getFilesDir(), SNAPSHOT_TOP_LEVEL_DIRECTORY); FileUtils.deleteContentsAndDir(file); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java index c09e09c8404f..46eaba7dace6 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java @@ -117,8 +117,12 @@ public class PlatformKeyManagerTest { @After public void tearDown() { - mRecoverableKeyStoreDb.close(); - mDatabaseFile.delete(); + if (mRecoverableKeyStoreDb != null) { + mRecoverableKeyStoreDb.close(); + } + if (mDatabaseFile != null) { + mDatabaseFile.delete(); + } } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java index 64130266b2c4..e6a6e36e75d6 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java @@ -89,8 +89,12 @@ public class RecoverableKeyGeneratorTest { keyStore.load(/*param=*/ null); keyStore.deleteEntry(WRAPPING_KEY_ALIAS); - mRecoverableKeyStoreDb.close(); - mDatabaseFile.delete(); + if (mRecoverableKeyStoreDb != null) { + mRecoverableKeyStoreDb.close(); + } + if (mDatabaseFile != null) { + mDatabaseFile.delete(); + } } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index 7641fb957cc8..878c838e734b 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -230,9 +230,15 @@ public class RecoverableKeyStoreManagerTest { @After public void tearDown() { - mRemoteLockscreenValidationSessionStorage.finishSession(mUserId); - mRecoverableKeyStoreDb.close(); - mDatabaseFile.delete(); + if (mRemoteLockscreenValidationSessionStorage != null) { + mRemoteLockscreenValidationSessionStorage.finishSession(mUserId); + } + if (mRecoverableKeyStoreDb != null) { + mRecoverableKeyStoreDb.close(); + } + if (mDatabaseFile != null) { + mDatabaseFile.delete(); + } } @Test diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java index bbd9223718ae..fb98fab52ca0 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbHelperTest.java @@ -18,6 +18,8 @@ package com.android.server.locksettings.recoverablekeystore.storage; import static com.google.common.truth.Truth.assertThat; +import static java.nio.charset.StandardCharsets.UTF_8; + import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; @@ -36,8 +38,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import static java.nio.charset.StandardCharsets.UTF_8; - @SmallTest @RunWith(AndroidJUnit4.class) public class RecoverableKeyStoreDbHelperTest { @@ -110,7 +110,9 @@ public class RecoverableKeyStoreDbHelperTest { @After public void tearDown() throws Exception { - mDatabase.close(); + if (mDatabase != null) { + mDatabase.close(); + } } private void createV2Tables() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java index 8bc14fc54ae1..a77d8bcd3875 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java @@ -72,8 +72,12 @@ public class RecoverableKeyStoreDbTest { @After public void tearDown() { - mRecoverableKeyStoreDb.close(); - mDatabaseFile.delete(); + if (mRecoverableKeyStoreDb != null) { + mRecoverableKeyStoreDb.close(); + } + if (mDatabaseFile != null) { + mDatabaseFile.delete(); + } } @Test diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java index b2e296a36b93..2912a0762761 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayConstraintsTests.java @@ -19,6 +19,7 @@ package com.android.server.om; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.content.om.OverlayConstraint.TYPE_DEVICE_ID; import static android.content.om.OverlayConstraint.TYPE_DISPLAY_ID; +import static android.util.TypedValue.TYPE_STRING; import static android.view.Display.DEFAULT_DISPLAY; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; @@ -28,6 +29,9 @@ import static junit.framework.Assert.assertNotNull; import static org.testng.Assert.assertThrows; +import android.app.Activity; +import android.companion.virtual.VirtualDeviceManager; +import android.content.Context; import android.content.om.FabricatedOverlay; import android.content.om.OverlayConstraint; import android.content.om.OverlayIdentifier; @@ -35,12 +39,12 @@ import android.content.om.OverlayInfo; import android.content.om.OverlayManager; import android.content.om.OverlayManagerTransaction; import android.content.res.Flags; +import android.content.res.Resources; import android.os.UserHandle; 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.util.TypedValue; +import android.view.Display; +import android.virtualdevice.cts.common.VirtualDeviceRule; import junitparams.JUnitParamsRunner; import junitparams.Parameters; @@ -53,20 +57,28 @@ import org.junit.runner.RunWith; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeoutException; @RunWith(JUnitParamsRunner.class) public class OverlayConstraintsTests { + private static final String RESOURCE_NAME = "string/module_2_name"; + private static final String RESOURCE_DEFAULT_VALUE = "module_2_name"; + private static final String RESOURCE_OVERLAID_VALUE = "hello"; + private static final long TIMEOUT_MILLIS = 2000L; @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + public final VirtualDeviceRule mVirtualDeviceRule = VirtualDeviceRule.createDefault(); private OverlayManager mOverlayManager; private UserHandle mUserHandle; private OverlayIdentifier mOverlayIdentifier = null; + private final String mPackageName = getApplicationContext().getPackageName(); @Before public void setUp() throws Exception { - mOverlayManager = getApplicationContext().getSystemService(OverlayManager.class); + final Context context = getApplicationContext(); + mOverlayManager = context.getSystemService(OverlayManager.class); mUserHandle = UserHandle.of(UserHandle.myUserId()); } @@ -79,6 +91,7 @@ public class OverlayConstraintsTests { .build(); mOverlayManager.commit(transaction); mOverlayIdentifier = null; + waitForResourceValue(RESOURCE_DEFAULT_VALUE, getApplicationContext()); } } @@ -161,13 +174,161 @@ public class OverlayConstraintsTests { List.of(new OverlayConstraint(TYPE_DISPLAY_ID, DEFAULT_DISPLAY)))); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS) + public void enableOverlayWithoutConstraints_appliesOverlayWithoutConstraints() + throws Exception { + enableOverlay(Collections.emptyList()); + + // Assert than the overlay is applied for both default device context and virtual + // device context. + final Context context = getApplicationContext(); + waitForResourceValue(RESOURCE_OVERLAID_VALUE, context); + VirtualDeviceManager.VirtualDevice virtualDevice = + mVirtualDeviceRule.createManagedVirtualDevice(); + final Context deviceContext = context.createDeviceContext(virtualDevice.getDeviceId()); + waitForResourceValue(RESOURCE_OVERLAID_VALUE, deviceContext); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS) + public void enableOverlayWithConstraints_withTypeDeviceId_appliesOverlayWithConstraints() + throws Exception { + final int deviceId1 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId(); + final int deviceId2 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId(); + enableOverlay(List.of(new OverlayConstraint(TYPE_DEVICE_ID, deviceId1), + new OverlayConstraint(TYPE_DEVICE_ID, deviceId2))); + + // Assert than the overlay is not applied for contexts not associated with the above + // devices. + final Context context = getApplicationContext(); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context); + final int deviceId3 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId(); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context.createDeviceContext(deviceId3)); + + // Assert than the overlay is applied for contexts associated with the above devices. + waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDeviceContext(deviceId1)); + waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDeviceContext(deviceId2)); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS) + public void enableOverlayWithConstraints_withTypeDisplayId_appliesOverlayWithConstraints() + throws Exception { + final Display display1 = + mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay(); + final Display display2 = + mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay(); + enableOverlay(List.of(new OverlayConstraint(TYPE_DISPLAY_ID, display1.getDisplayId()), + new OverlayConstraint(TYPE_DISPLAY_ID, display2.getDisplayId()))); + + // Assert than the overlay is not applied for contexts not associated with the above + // displays. + final Context context = getApplicationContext(); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context); + final Display display3 = + mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay(); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context.createDisplayContext(display3)); + + // Assert than the overlay is applied for contexts associated with the above displays. + waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDisplayContext(display1)); + waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDisplayContext(display2)); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS) + public void enableOverlayWithConstraints_withTypesDisplayIdAndDeviceId_appliesOverlayWithConstraints() + throws Exception { + final Display display1 = + mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay(); + final int deviceId1 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId(); + enableOverlay(List.of(new OverlayConstraint(TYPE_DISPLAY_ID, display1.getDisplayId()), + new OverlayConstraint(TYPE_DEVICE_ID, deviceId1))); + + // Assert than the overlay is not applied for contexts not associated with the above + // display or device. + final Context context = getApplicationContext(); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context); + final Display display2 = + mVirtualDeviceRule.createManagedUnownedVirtualDisplay().getDisplay(); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context.createDisplayContext(display2)); + final int deviceId2 = mVirtualDeviceRule.createManagedVirtualDevice().getDeviceId(); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, context.createDeviceContext(deviceId2)); + + // Assert than the overlay is applied for contexts associated with the above display or + // device. + waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDisplayContext(display1)); + waitForResourceValue(RESOURCE_OVERLAID_VALUE, context.createDeviceContext(deviceId1)); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS) + public void enableOverlayWithConstraints_withTypeDisplayId_appliesForActivityOnDisplay() + throws Exception { + final Display display = + mVirtualDeviceRule.createManagedUnownedVirtualDisplay( + VirtualDeviceRule.createTrustedVirtualDisplayConfigBuilder()) + .getDisplay(); + final Activity activityOnDefaultDisplay = mVirtualDeviceRule.startActivityOnDisplaySync( + DEFAULT_DISPLAY, Activity.class); + final Activity activityOnVirtualDisplay = mVirtualDeviceRule.startActivityOnDisplaySync( + display.getDisplayId(), Activity.class); + + enableOverlay(List.of(new OverlayConstraint(TYPE_DISPLAY_ID, display.getDisplayId()))); + + // Assert than the overlay is not applied for any existing activity on the default display. + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, activityOnDefaultDisplay); + // Assert than the overlay is applied for any existing activity on the virtual display. + waitForResourceValue(RESOURCE_OVERLAID_VALUE, activityOnVirtualDisplay); + + // Assert than the overlay is not applied for any new activity on the default display. + final Activity newActivityOnDefaultDisplay = mVirtualDeviceRule.startActivityOnDisplaySync( + DEFAULT_DISPLAY, Activity.class); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, newActivityOnDefaultDisplay); + // Assert than the overlay is applied for any new activity on the virtual display. + final Activity newActivityOnVirtualDisplay = mVirtualDeviceRule.startActivityOnDisplaySync( + display.getDisplayId(), Activity.class); + waitForResourceValue(RESOURCE_OVERLAID_VALUE, newActivityOnVirtualDisplay); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_RRO_CONSTRAINTS) + public void enableOverlayWithConstraints_withTypeDeviceId_appliesForActivityOnDevice() + throws Exception { + final VirtualDeviceManager.VirtualDevice device = + mVirtualDeviceRule.createManagedVirtualDevice(); + final Display display = + mVirtualDeviceRule.createManagedVirtualDisplay(device, + VirtualDeviceRule.createTrustedVirtualDisplayConfigBuilder()) + .getDisplay(); + final Activity activityOnDefaultDevice = mVirtualDeviceRule.startActivityOnDisplaySync( + DEFAULT_DISPLAY, Activity.class); + final Activity activityOnVirtualDevice = mVirtualDeviceRule.startActivityOnDisplaySync( + display.getDisplayId(), Activity.class); + + enableOverlay(List.of(new OverlayConstraint(TYPE_DEVICE_ID, device.getDeviceId()))); + + // Assert than the overlay is not applied for any existing activity on the default device. + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, activityOnDefaultDevice); + // Assert than the overlay is applied for any existing activity on the virtual device. + waitForResourceValue(RESOURCE_OVERLAID_VALUE, activityOnVirtualDevice); + + // Assert than the overlay is not applied for any new activity on the default device. + final Activity newActivityOnDefaultDevice = mVirtualDeviceRule.startActivityOnDisplaySync( + DEFAULT_DISPLAY, Activity.class); + ensureResourceValueStaysAt(RESOURCE_DEFAULT_VALUE, newActivityOnDefaultDevice); + // Assert than the overlay is applied for any new activity on the virtual device. + final Activity newActivityOnVirtualDevice = mVirtualDeviceRule.startActivityOnDisplaySync( + display.getDisplayId(), Activity.class); + waitForResourceValue(RESOURCE_OVERLAID_VALUE, newActivityOnVirtualDevice); + } + private FabricatedOverlay createFabricatedOverlay() { - String packageName = getApplicationContext().getPackageName(); FabricatedOverlay fabricatedOverlay = new FabricatedOverlay.Builder( - packageName, "testOverlay" /* name */, packageName) + mPackageName, "testOverlay" /* name */, mPackageName) .build(); - fabricatedOverlay.setResourceValue("string/module_2_name" /* resourceName */, - TypedValue.TYPE_STRING, "hello" /* value */, null /* configuration */); + fabricatedOverlay.setResourceValue(RESOURCE_NAME, TYPE_STRING, RESOURCE_OVERLAID_VALUE, + null /* configuration */); return fabricatedOverlay; } @@ -183,6 +344,37 @@ public class OverlayConstraintsTests { mOverlayIdentifier = fabricatedOverlay.getIdentifier(); } + private static void waitForResourceValue(final String expectedValue, Context context) + throws TimeoutException { + final long endTime = System.currentTimeMillis() + TIMEOUT_MILLIS; + final Resources resources = context.getResources(); + final int resourceId = getResourceId(context); + String resourceValue = null; + while (System.currentTimeMillis() < endTime) { + resourceValue = resources.getString(resourceId); + if (Objects.equals(resourceValue, expectedValue)) { + return; + } + } + throw new TimeoutException("Timed out waiting for '" + RESOURCE_NAME + "' value to equal '" + + expectedValue + "': current value is '" + resourceValue + "'"); + } + + private static void ensureResourceValueStaysAt(final String expectedValue, Context context) { + final long endTime = System.currentTimeMillis() + TIMEOUT_MILLIS; + final Resources resources = context.getResources(); + final int resourceId = getResourceId(context); + String resourceValue; + while (System.currentTimeMillis() < endTime) { + resourceValue = resources.getString(resourceId); + assertEquals(expectedValue, resourceValue); + } + } + + private static int getResourceId(Context context) { + return context.getResources().getIdentifier(RESOURCE_NAME, "", context.getPackageName()); + } + private static List<OverlayConstraint>[] getAllConstraintLists() { return new List[]{ Collections.emptyList(), diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 3ef360a752f6..da14e451d656 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -95,8 +95,8 @@ import android.test.mock.MockContext; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; +import android.util.SparseArray; -import com.android.internal.infra.AndroidFuture; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.LauncherAppsService.LauncherAppsImpl; @@ -110,6 +110,7 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -149,6 +150,9 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected static final String MAIN_ACTIVITY_CLASS = "MainActivity"; protected static final String PIN_CONFIRM_ACTIVITY_CLASS = "PinConfirmActivity"; + private byte[] mBaseState; + protected final SparseArray<byte[]> mUserStates = new SparseArray<>(); + // public for mockito public class BaseContext extends MockContext { @Override @@ -287,6 +291,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { final ServiceContext mContext; IUidObserver mUidObserver; + public ShortcutServiceTestable(ServiceContext context, Looper looper) { super(context, looper, /* onyForPackageManagerApis */ false); mContext = context; @@ -567,6 +572,58 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { // During tests, WTF is fatal. fail(message + " exception: " + th + "\n" + Log.getStackTraceString(th)); } + + @Override + void injectSaveBaseState() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + saveBaseStateAsXml(baos); + } catch (Exception e) { + throw new RuntimeException(e); + } + mBaseState = baos.toByteArray(); + } + + @Override + protected void injectLoadBaseState() { + if (mBaseState == null) { + return; + } + ByteArrayInputStream bais = new ByteArrayInputStream(mBaseState); + try { + loadBaseStateAsXml(bais); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + protected void injectSaveUser(@UserIdInt int userId) { + synchronized (mServiceLock) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + saveUserInternalLocked(userId, baos, /* forBackup= */ false); + cleanupDanglingBitmapDirectoriesLocked(userId); + } catch (Exception e) { + throw new RuntimeException(e); + } + mUserStates.put(userId, baos.toByteArray()); + } + } + + @Override + protected ShortcutUser injectLoadUserLocked(@UserIdInt int userId) { + final byte[] userState = mUserStates.get(userId); + if (userState == null) { + return null; + } + ByteArrayInputStream bais = new ByteArrayInputStream(userState); + try { + return loadUserInternal(userId, bais, /* forBackup= */ false); + } catch (Exception e) { + throw new RuntimeException(e); + } + } } /** ShortcutManager with injection override methods. */ diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index f536cae53e3a..58f762204c27 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -201,7 +201,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50; assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL); - mService.saveBaseState(); + mService.injectSaveBaseState(); dumpBaseStateFile(); diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 3b32701b5169..f5690b77d2fe 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -54,9 +54,7 @@ import androidx.test.filters.SmallTest; import com.android.frameworks.servicestests.R; import java.io.File; -import java.io.FileWriter; import java.io.IOException; -import java.io.Writer; import java.util.Locale; /** @@ -2358,12 +2356,10 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { * can still be read. */ public void testLoadLegacySavedFile() throws Exception { - final File path = mService.getUserFile(USER_10).getBaseFile(); - path.getParentFile().mkdirs(); - try (Writer w = new FileWriter(path)) { - w.write(readTestAsset("shortcut/shortcut_legacy_file.xml")); - }; + final String legacyFile = readTestAsset("shortcut/shortcut_legacy_file.xml"); + mUserStates.put(USER_10, legacyFile.getBytes()); initService(); + mService.handleUnlockUser(USER_10); runWithCaller(CALLING_PACKAGE_1, USER_10, () -> { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 5dea44d6ebf4..67e85ff2445d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -4495,6 +4495,27 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test + public void testBubblePreference_sameVersionWithSAWPermission() throws Exception { + when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(), + anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED); + + final String xml = "<ranking version=\"4\">\n" + + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n" + + "<channel id=\"someId\" name=\"hi\"" + + " importance=\"3\"/>" + + "</package>" + + "</ranking>"; + TypedXmlPullParser parser = Xml.newFastPullParser(); + parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), + null); + parser.nextTag(); + mHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O)); + assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); + } + + @Test public void testBubblePreference_upgradeWithSAWThenUserOverride() throws Exception { when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(), anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java index 4c1544f14667..67efb9e76692 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java @@ -488,33 +488,33 @@ public class ZenModeConfigTest extends UiServiceTestCase { ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); rule.zenPolicy = null; rule.zenDeviceEffects = null; - assertThat(rule.canBeUpdatedByApp()).isTrue(); + assertThat(rule.isUserModified()).isFalse(); rule.userModifiedFields = 1; - assertThat(rule.canBeUpdatedByApp()).isFalse(); + assertThat(rule.isUserModified()).isTrue(); } @Test public void testCanBeUpdatedByApp_policyModified() throws Exception { ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); rule.zenPolicy = new ZenPolicy(); - assertThat(rule.canBeUpdatedByApp()).isTrue(); + assertThat(rule.isUserModified()).isFalse(); rule.zenPolicyUserModifiedFields = 1; - assertThat(rule.canBeUpdatedByApp()).isFalse(); + assertThat(rule.isUserModified()).isTrue(); } @Test public void testCanBeUpdatedByApp_deviceEffectsModified() throws Exception { ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); rule.zenDeviceEffects = new ZenDeviceEffects.Builder().build(); - assertThat(rule.canBeUpdatedByApp()).isTrue(); + assertThat(rule.isUserModified()).isFalse(); rule.zenDeviceEffectsUserModifiedFields = 1; - assertThat(rule.canBeUpdatedByApp()).isFalse(); + assertThat(rule.isUserModified()).isTrue(); } @Test @@ -563,6 +563,9 @@ public class ZenModeConfigTest extends UiServiceTestCase { rule.deletionInstant = Instant.ofEpochMilli(1701790147000L); if (Flags.modesUi()) { rule.disabledOrigin = ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI; + if (Flags.modesCleanupImplicit()) { + rule.lastActivation = Instant.ofEpochMilli(456); + } } config.automaticRules.put(rule.id, rule); @@ -600,6 +603,9 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(rule.deletionInstant, ruleActual.deletionInstant); if (Flags.modesUi()) { assertEquals(rule.disabledOrigin, ruleActual.disabledOrigin); + if (Flags.modesCleanupImplicit()) { + assertEquals(rule.lastActivation, ruleActual.lastActivation); + } } if (Flags.backupRestoreLogging()) { verify(logger).logItemsBackedUp(DATA_TYPE_ZEN_RULES, 2); @@ -633,6 +639,9 @@ public class ZenModeConfigTest extends UiServiceTestCase { rule.deletionInstant = Instant.ofEpochMilli(1701790147000L); if (Flags.modesUi()) { rule.disabledOrigin = ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI; + if (Flags.modesCleanupImplicit()) { + rule.lastActivation = Instant.ofEpochMilli(789); + } } Parcel parcel = Parcel.obtain(); @@ -664,6 +673,9 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(rule.deletionInstant, parceled.deletionInstant); if (Flags.modesUi()) { assertEquals(rule.disabledOrigin, parceled.disabledOrigin); + if (Flags.modesCleanupImplicit()) { + assertEquals(rule.lastActivation, parceled.lastActivation); + } } assertEquals(rule, parceled); @@ -746,6 +758,9 @@ public class ZenModeConfigTest extends UiServiceTestCase { rule.deletionInstant = Instant.ofEpochMilli(1701790147000L); if (Flags.modesUi()) { rule.disabledOrigin = ZenModeConfig.ORIGIN_APP; + if (Flags.modesCleanupImplicit()) { + rule.lastActivation = Instant.ofEpochMilli(123); + } } ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -781,6 +796,9 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(rule.deletionInstant, fromXml.deletionInstant); if (Flags.modesUi()) { assertEquals(rule.disabledOrigin, fromXml.disabledOrigin); + if (Flags.modesCleanupImplicit()) { + assertEquals(rule.lastActivation, fromXml.lastActivation); + } } } @@ -908,7 +926,7 @@ public class ZenModeConfigTest extends UiServiceTestCase { ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); rule.userModifiedFields |= AutomaticZenRule.FIELD_NAME; assertThat(rule.userModifiedFields).isEqualTo(1); - assertThat(rule.canBeUpdatedByApp()).isFalse(); + assertThat(rule.isUserModified()).isTrue(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); writeRuleXml(rule, baos); @@ -916,7 +934,7 @@ public class ZenModeConfigTest extends UiServiceTestCase { ZenModeConfig.ZenRule fromXml = readRuleXml(bais); assertThat(fromXml.userModifiedFields).isEqualTo(rule.userModifiedFields); - assertThat(fromXml.canBeUpdatedByApp()).isFalse(); + assertThat(fromXml.isUserModified()).isTrue(); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java index 8a5f80cb3e49..6d0bf8b322fd 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java @@ -475,7 +475,8 @@ public class ZenModeDiffTest extends UiServiceTestCase { // "Metadata" fields are never compared. Set<String> exemptFields = new LinkedHashSet<>( Set.of("userModifiedFields", "zenPolicyUserModifiedFields", - "zenDeviceEffectsUserModifiedFields", "deletionInstant", "disabledOrigin")); + "zenDeviceEffectsUserModifiedFields", "deletionInstant", "disabledOrigin", + "lastActivation")); // Flagged fields are only compared if their flag is on. if (Flags.modesUi()) { exemptFields.add(RuleDiff.FIELD_SNOOZING); // Obsolete. diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 4d2f105e27b3..0ab11e0cbe3d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -23,6 +23,7 @@ import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME; import static android.app.AutomaticZenRule.TYPE_THEATER; import static android.app.AutomaticZenRule.TYPE_UNKNOWN; import static android.app.Flags.FLAG_BACKUP_RESTORE_LOGGING; +import static android.app.Flags.FLAG_MODES_CLEANUP_IMPLICIT; import static android.app.Flags.FLAG_MODES_MULTIUSER; import static android.app.Flags.FLAG_MODES_UI; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED; @@ -124,7 +125,10 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; +import static java.time.temporal.ChronoUnit.DAYS; + import android.Manifest; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.AlarmManager; @@ -219,7 +223,6 @@ import java.io.Reader; import java.io.StringWriter; import java.time.Instant; import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Calendar; import java.util.LinkedList; @@ -2233,8 +2236,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelper.mConfig.automaticRules.put(implicitRuleBeforeModesUi.id, implicitRuleBeforeModesUi); // Plus one other normal rule. - ZenRule anotherRule = newZenRule("other_pkg", Instant.now(), null); - anotherRule.id = "other_rule"; + ZenRule anotherRule = newZenRule("other_rule", "other_pkg", Instant.now()); anotherRule.iconResName = "other_icon"; anotherRule.type = TYPE_IMMERSIVE; mZenModeHelper.mConfig.automaticRules.put(anotherRule.id, anotherRule); @@ -2271,8 +2273,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { implicitRuleWithModesUi); // Plus one other normal rule. - ZenRule anotherRule = newZenRule("other_pkg", Instant.now(), null); - anotherRule.id = "other_rule"; + ZenRule anotherRule = newZenRule("other_rule", "other_pkg", Instant.now()); anotherRule.iconResName = "other_icon"; anotherRule.type = TYPE_IMMERSIVE; mZenModeHelper.mConfig.automaticRules.put(anotherRule.id, anotherRule); @@ -4611,7 +4612,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue(); ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); - assertThat(storedRule.canBeUpdatedByApp()).isTrue(); + assertThat(storedRule.isUserModified()).isFalse(); } @Test @@ -4719,7 +4720,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { STATE_DISALLOW); ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); - assertThat(storedRule.canBeUpdatedByApp()).isFalse(); + assertThat(storedRule.isUserModified()).isTrue(); assertThat(storedRule.zenPolicyUserModifiedFields).isEqualTo( ZenPolicy.FIELD_ALLOW_CHANNELS | ZenPolicy.FIELD_PRIORITY_CATEGORY_REMINDERS @@ -4761,7 +4762,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue(); ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(ruleId); - assertThat(storedRule.canBeUpdatedByApp()).isFalse(); + assertThat(storedRule.isUserModified()).isTrue(); assertThat(storedRule.zenDeviceEffectsUserModifiedFields).isEqualTo( ZenDeviceEffects.FIELD_GRAYSCALE); } @@ -5713,8 +5714,8 @@ public class ZenModeHelperTest extends UiServiceTestCase { // Start with deleted rules from 2 different packages. Instant now = Instant.ofEpochMilli(1701796461000L); - ZenRule pkg1Rule = newZenRule("pkg1", now.minus(1, ChronoUnit.DAYS), now); - ZenRule pkg2Rule = newZenRule("pkg2", now.minus(2, ChronoUnit.DAYS), now); + ZenRule pkg1Rule = newDeletedZenRule("1", "pkg1", now.minus(1, DAYS), now); + ZenRule pkg2Rule = newDeletedZenRule("2", "pkg2", now.minus(2, DAYS), now); mZenModeHelper.mConfig.deletedRules.put(ZenModeConfig.deletedRuleKey(pkg1Rule), pkg1Rule); mZenModeHelper.mConfig.deletedRules.put(ZenModeConfig.deletedRuleKey(pkg2Rule), pkg2Rule); @@ -5832,9 +5833,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testRuleCleanup() throws Exception { Instant now = Instant.ofEpochMilli(1701796461000L); - Instant yesterday = now.minus(1, ChronoUnit.DAYS); - Instant aWeekAgo = now.minus(7, ChronoUnit.DAYS); - Instant twoMonthsAgo = now.minus(60, ChronoUnit.DAYS); + Instant yesterday = now.minus(1, DAYS); + Instant aWeekAgo = now.minus(7, DAYS); + Instant twoMonthsAgo = now.minus(60, DAYS); mTestClock.setNowMillis(now.toEpochMilli()); when(mPackageManager.getPackageInfo(eq("good_pkg"), anyInt())) @@ -5847,24 +5848,28 @@ public class ZenModeHelperTest extends UiServiceTestCase { config.user = 42; mZenModeHelper.mConfigs.put(42, config); // okay rules (not deleted, package exists, with a range of creation dates). - config.automaticRules.put("ar1", newZenRule("good_pkg", now, null)); - config.automaticRules.put("ar2", newZenRule("good_pkg", yesterday, null)); - config.automaticRules.put("ar3", newZenRule("good_pkg", twoMonthsAgo, null)); + config.automaticRules.put("ar1", newZenRule("ar1", "good_pkg", now)); + config.automaticRules.put("ar2", newZenRule("ar2", "good_pkg", yesterday)); + config.automaticRules.put("ar3", newZenRule("ar3", "good_pkg", twoMonthsAgo)); // newish rules for a missing package - config.automaticRules.put("ar4", newZenRule("bad_pkg", yesterday, null)); + config.automaticRules.put("ar4", newZenRule("ar4", "bad_pkg", yesterday)); // oldish rules belonging to a missing package - config.automaticRules.put("ar5", newZenRule("bad_pkg", aWeekAgo, null)); + config.automaticRules.put("ar5", newZenRule("ar5", "bad_pkg", aWeekAgo)); // rules deleted recently - config.deletedRules.put("del1", newZenRule("good_pkg", twoMonthsAgo, yesterday)); - config.deletedRules.put("del2", newZenRule("good_pkg", twoMonthsAgo, aWeekAgo)); + config.deletedRules.put("del1", + newDeletedZenRule("del1", "good_pkg", twoMonthsAgo, yesterday)); + config.deletedRules.put("del2", + newDeletedZenRule("del2", "good_pkg", twoMonthsAgo, aWeekAgo)); // rules deleted a long time ago - config.deletedRules.put("del3", newZenRule("good_pkg", twoMonthsAgo, twoMonthsAgo)); + config.deletedRules.put("del3", + newDeletedZenRule("del3", "good_pkg", twoMonthsAgo, twoMonthsAgo)); // rules for a missing package, created recently and deleted recently - config.deletedRules.put("del4", newZenRule("bad_pkg", yesterday, now)); + config.deletedRules.put("del4", newDeletedZenRule("del4", "bad_pkg", yesterday, now)); // rules for a missing package, created a long time ago and deleted recently - config.deletedRules.put("del5", newZenRule("bad_pkg", twoMonthsAgo, now)); + config.deletedRules.put("del5", newDeletedZenRule("del5", "bad_pkg", twoMonthsAgo, now)); // rules for a missing package, created a long time ago and deleted a long time ago - config.deletedRules.put("del6", newZenRule("bad_pkg", twoMonthsAgo, twoMonthsAgo)); + config.deletedRules.put("del6", + newDeletedZenRule("del6", "bad_pkg", twoMonthsAgo, twoMonthsAgo)); mZenModeHelper.onUserSwitched(42); // copies config and cleans it up. @@ -5874,14 +5879,115 @@ public class ZenModeHelperTest extends UiServiceTestCase { .containsExactly("del1", "del2", "del4"); } - private static ZenRule newZenRule(String pkg, Instant createdAt, @Nullable Instant deletedAt) { + @Test + @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT}) + public void testRuleCleanup_removesNotRecentlyUsedNotModifiedImplicitRules() throws Exception { + Instant now = Instant.ofEpochMilli(1701796461000L); + Instant yesterday = now.minus(1, DAYS); + Instant aWeekAgo = now.minus(7, DAYS); + Instant twoMonthsAgo = now.minus(60, DAYS); + Instant aYearAgo = now.minus(365, DAYS); + mTestClock.setNowMillis(now.toEpochMilli()); + when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(new PackageInfo()); + + // Set up a config to be loaded, containing a bunch of implicit rules + ZenModeConfig config = new ZenModeConfig(); + config.user = 42; + mZenModeHelper.mConfigs.put(42, config); + // used recently + ZenRule usedRecently1 = newImplicitZenRule("pkg1", aYearAgo, yesterday); + ZenRule usedRecently2 = newImplicitZenRule("pkg2", aYearAgo, aWeekAgo); + config.automaticRules.put(usedRecently1.id, usedRecently1); + config.automaticRules.put(usedRecently2.id, usedRecently2); + // not used in a long time + ZenRule longUnused = newImplicitZenRule("pkg3", aYearAgo, twoMonthsAgo); + config.automaticRules.put(longUnused.id, longUnused); + // created a long time ago, before lastActivation tracking + ZenRule oldAndLastUsageUnknown = newImplicitZenRule("pkg4", twoMonthsAgo, null); + config.automaticRules.put(oldAndLastUsageUnknown.id, oldAndLastUsageUnknown); + // created a short time ago, before lastActivation tracking + ZenRule newAndLastUsageUnknown = newImplicitZenRule("pkg5", aWeekAgo, null); + config.automaticRules.put(newAndLastUsageUnknown.id, newAndLastUsageUnknown); + // not used in a long time, but was customized by user + ZenRule longUnusedButCustomized = newImplicitZenRule("pkg6", aYearAgo, twoMonthsAgo); + longUnusedButCustomized.zenPolicyUserModifiedFields = ZenPolicy.FIELD_CONVERSATIONS; + config.automaticRules.put(longUnusedButCustomized.id, longUnusedButCustomized); + // created a long time ago, before lastActivation tracking, and was customized by user + ZenRule oldAndLastUsageUnknownAndCustomized = newImplicitZenRule("pkg7", twoMonthsAgo, + null); + oldAndLastUsageUnknownAndCustomized.userModifiedFields = AutomaticZenRule.FIELD_ICON; + config.automaticRules.put(oldAndLastUsageUnknownAndCustomized.id, + oldAndLastUsageUnknownAndCustomized); + + mZenModeHelper.onUserSwitched(42); // copies config and cleans it up. + + // The recently used OR modified OR last-used-unknown rules stay. + assertThat(mZenModeHelper.mConfig.automaticRules.values()) + .comparingElementsUsing(IGNORE_METADATA) + .containsExactly(usedRecently1, usedRecently2, oldAndLastUsageUnknown, + newAndLastUsageUnknown, longUnusedButCustomized, + oldAndLastUsageUnknownAndCustomized); + } + + @Test + @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT}) + public void testRuleCleanup_assignsLastActivationToImplicitRules() throws Exception { + Instant now = Instant.ofEpochMilli(1701796461000L); + Instant aWeekAgo = now.minus(7, DAYS); + Instant aYearAgo = now.minus(365, DAYS); + mTestClock.setNowMillis(now.toEpochMilli()); + when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn(new PackageInfo()); + + // Set up a config to be loaded, containing implicit rules. + ZenModeConfig config = new ZenModeConfig(); + config.user = 42; + mZenModeHelper.mConfigs.put(42, config); + // with last activation known + ZenRule usedRecently = newImplicitZenRule("pkg1", aYearAgo, aWeekAgo); + config.automaticRules.put(usedRecently.id, usedRecently); + // created a long time ago, with last activation unknown + ZenRule oldAndLastUsageUnknown = newImplicitZenRule("pkg4", aYearAgo, null); + config.automaticRules.put(oldAndLastUsageUnknown.id, oldAndLastUsageUnknown); + // created a short time ago, with last activation unknown + ZenRule newAndLastUsageUnknown = newImplicitZenRule("pkg5", aWeekAgo, null); + config.automaticRules.put(newAndLastUsageUnknown.id, newAndLastUsageUnknown); + + mZenModeHelper.onUserSwitched(42); // copies config and cleans it up. + + // All rules stayed. + usedRecently = getZenRule(usedRecently.id); + oldAndLastUsageUnknown = getZenRule(oldAndLastUsageUnknown.id); + newAndLastUsageUnknown = getZenRule(newAndLastUsageUnknown.id); + + // The rules with an unknown last usage have been assigned a placeholder one. + assertThat(usedRecently.lastActivation).isEqualTo(aWeekAgo); + assertThat(oldAndLastUsageUnknown.lastActivation).isEqualTo(now); + assertThat(newAndLastUsageUnknown.lastActivation).isEqualTo(now); + } + + private static ZenRule newDeletedZenRule(String id, String pkg, Instant createdAt, + @NonNull Instant deletedAt) { + ZenRule rule = newZenRule(id, pkg, createdAt); + rule.deletionInstant = deletedAt; + return rule; + } + + private static ZenRule newImplicitZenRule(String pkg, @NonNull Instant createdAt, + @Nullable Instant lastActivatedAt) { + ZenRule implicitRule = newZenRule(implicitRuleId(pkg), pkg, createdAt); + implicitRule.lastActivation = lastActivatedAt; + return implicitRule; + } + + private static ZenRule newZenRule(String id, String pkg, Instant createdAt) { ZenRule rule = new ZenRule(); + rule.id = id; rule.pkg = pkg; rule.creationTime = createdAt.toEpochMilli(); rule.enabled = true; - rule.deletionInstant = deletedAt; + rule.deletionInstant = null; // Plus stuff so that isValidAutomaticRule() passes - rule.name = "A rule from " + pkg + " created on " + createdAt; + rule.name = "Rule " + id; rule.conditionId = Uri.parse(rule.name); return rule; } @@ -5919,11 +6025,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void getAutomaticZenRuleState_notOwnedRule_returnsStateUnknown() { // Assume existence of a system-owned rule that is currently ACTIVE. - ZenRule systemRule = newZenRule("android", Instant.now(), null); + ZenRule systemRule = newZenRule("systemRule", "android", Instant.now()); systemRule.zenMode = ZEN_MODE_ALARMS; systemRule.condition = new Condition(systemRule.conditionId, "on", Condition.STATE_TRUE); ZenModeConfig config = mZenModeHelper.mConfig.copy(); - config.automaticRules.put("systemRule", systemRule); + config.automaticRules.put(systemRule.id, systemRule); mZenModeHelper.setConfig(config, null, ORIGIN_INIT, "", SYSTEM_UID); assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS); @@ -5935,11 +6041,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void setAutomaticZenRuleState_idForNotOwnedRule_ignored() { // Assume existence of an other-package-owned rule that is currently ACTIVE. assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF); - ZenRule otherRule = newZenRule("another.package", Instant.now(), null); + ZenRule otherRule = newZenRule("otherRule", "another.package", Instant.now()); otherRule.zenMode = ZEN_MODE_ALARMS; otherRule.condition = new Condition(otherRule.conditionId, "on", Condition.STATE_TRUE); ZenModeConfig config = mZenModeHelper.mConfig.copy(); - config.automaticRules.put("otherRule", otherRule); + config.automaticRules.put(otherRule.id, otherRule); mZenModeHelper.setConfig(config, null, ORIGIN_INIT, "", SYSTEM_UID); assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS); @@ -5955,11 +6061,11 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void setAutomaticZenRuleStateFromConditionProvider_conditionForNotOwnedRule_ignored() { // Assume existence of an other-package-owned rule that is currently ACTIVE. assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF); - ZenRule otherRule = newZenRule("another.package", Instant.now(), null); + ZenRule otherRule = newZenRule("otherRule", "another.package", Instant.now()); otherRule.zenMode = ZEN_MODE_ALARMS; otherRule.condition = new Condition(otherRule.conditionId, "on", Condition.STATE_TRUE); ZenModeConfig config = mZenModeHelper.mConfig.copy(); - config.automaticRules.put("otherRule", otherRule); + config.automaticRules.put(otherRule.id, otherRule); mZenModeHelper.setConfig(config, null, ORIGIN_INIT, "", SYSTEM_UID); assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS); @@ -7255,6 +7361,125 @@ public class ZenModeHelperTest extends UiServiceTestCase { "config: setAzrStateFromCps: cond/cond (ORIGIN_APP) from uid " + CUSTOM_PKG_UID); } + @Test + @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT}) + public void setAutomaticZenRuleState_updatesLastActivation() { + String ruleOne = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg, + new AutomaticZenRule.Builder("rule", CONDITION_ID) + .setConfigurationActivity(new ComponentName(mPkg, "cls")) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .build(), + ORIGIN_APP, "reason", CUSTOM_PKG_UID); + String ruleTwo = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg, + new AutomaticZenRule.Builder("unrelated", Uri.parse("other.condition")) + .setConfigurationActivity(new ComponentName(mPkg, "cls")) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .build(), + ORIGIN_APP, "reason", CUSTOM_PKG_UID); + + assertThat(getZenRule(ruleOne).lastActivation).isNull(); + assertThat(getZenRule(ruleTwo).lastActivation).isNull(); + + Instant firstActivation = Instant.ofEpochMilli(100); + mTestClock.setNow(firstActivation); + mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleOne, CONDITION_TRUE, + ORIGIN_APP, CUSTOM_PKG_UID); + + assertThat(getZenRule(ruleOne).lastActivation).isEqualTo(firstActivation); + assertThat(getZenRule(ruleTwo).lastActivation).isNull(); + + mTestClock.setNow(Instant.ofEpochMilli(300)); + mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleOne, CONDITION_FALSE, + ORIGIN_APP, CUSTOM_PKG_UID); + + assertThat(getZenRule(ruleOne).lastActivation).isEqualTo(firstActivation); + assertThat(getZenRule(ruleTwo).lastActivation).isNull(); + + Instant secondActivation = Instant.ofEpochMilli(500); + mTestClock.setNow(secondActivation); + mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleOne, CONDITION_TRUE, + ORIGIN_APP, CUSTOM_PKG_UID); + + assertThat(getZenRule(ruleOne).lastActivation).isEqualTo(secondActivation); + assertThat(getZenRule(ruleTwo).lastActivation).isNull(); + } + + @Test + @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT}) + public void setManualZenMode_updatesLastActivation() { + assertThat(mZenModeHelper.mConfig.manualRule.lastActivation).isNull(); + Instant instant = Instant.ofEpochMilli(100); + mTestClock.setNow(instant); + + mZenModeHelper.setManualZenMode(UserHandle.CURRENT, ZEN_MODE_ALARMS, null, + ORIGIN_USER_IN_SYSTEMUI, "reason", "systemui", SYSTEM_UID); + + assertThat(mZenModeHelper.mConfig.manualRule.lastActivation).isEqualTo(instant); + } + + @Test + @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT}) + public void applyGlobalZenModeAsImplicitZenRule_updatesLastActivation() { + Instant instant = Instant.ofEpochMilli(100); + mTestClock.setNow(instant); + + mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME, + CUSTOM_PKG_UID, ZEN_MODE_ALARMS); + + ZenRule implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME)); + assertThat(implicitRule.lastActivation).isEqualTo(instant); + } + + @Test + @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT}) + public void setAutomaticZenRuleState_notChangingActiveState_doesNotUpdateLastActivation() { + String ruleId = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg, + new AutomaticZenRule.Builder("rule", CONDITION_ID) + .setConfigurationActivity(new ComponentName(mPkg, "cls")) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .build(), + ORIGIN_APP, "reason", CUSTOM_PKG_UID); + + assertThat(getZenRule(ruleId).lastActivation).isNull(); + + // Manual activation comes first + Instant firstActivation = Instant.ofEpochMilli(100); + mTestClock.setNow(firstActivation); + mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleId, CONDITION_TRUE, + ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID); + + assertThat(getZenRule(ruleId).lastActivation).isEqualTo(firstActivation); + + // Now the app says the rule should be active (assume it's on a schedule, and the app + // doesn't listen to broadcasts so it doesn't know an override was present). This doesn't + // change the activation state. + mTestClock.setNow(Instant.ofEpochMilli(300)); + mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, ruleId, CONDITION_TRUE, + ORIGIN_APP, CUSTOM_PKG_UID); + + assertThat(getZenRule(ruleId).lastActivation).isEqualTo(firstActivation); + } + + @Test + @EnableFlags({FLAG_MODES_UI, FLAG_MODES_CLEANUP_IMPLICIT}) + public void addOrUpdateRule_doesNotUpdateLastActivation() { + AutomaticZenRule azr = new AutomaticZenRule.Builder("rule", CONDITION_ID) + .setConfigurationActivity(new ComponentName(mPkg, "cls")) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .build(); + + String ruleId = mZenModeHelper.addAutomaticZenRule(UserHandle.CURRENT, mPkg, azr, + ORIGIN_APP, "reason", CUSTOM_PKG_UID); + + assertThat(getZenRule(ruleId).lastActivation).isNull(); + + mZenModeHelper.updateAutomaticZenRule(UserHandle.CURRENT, ruleId, + new AutomaticZenRule.Builder(azr).setName("New name").build(), ORIGIN_APP, "reason", + CUSTOM_PKG_UID); + + assertThat(getZenRule(ruleId).lastActivation).isNull(); + } + private static void addZenRule(ZenModeConfig config, String id, String ownerPkg, int zenMode, @Nullable ZenPolicy zenPolicy) { ZenRule rule = new ZenRule(); @@ -7272,22 +7497,27 @@ public class ZenModeHelperTest extends UiServiceTestCase { } private static final Correspondence<ZenRule, ZenRule> IGNORE_METADATA = - Correspondence.transforming(zr -> { - Parcel p = Parcel.obtain(); - try { - zr.writeToParcel(p, 0); - p.setDataPosition(0); - ZenRule copy = new ZenRule(p); - copy.creationTime = 0; - copy.userModifiedFields = 0; - copy.zenPolicyUserModifiedFields = 0; - copy.zenDeviceEffectsUserModifiedFields = 0; - return copy; - } finally { - p.recycle(); - } - }, - "Ignoring timestamp and userModifiedFields"); + Correspondence.transforming( + ZenModeHelperTest::cloneWithoutMetadata, + ZenModeHelperTest::cloneWithoutMetadata, + "Ignoring timestamps and userModifiedFields"); + + private static ZenRule cloneWithoutMetadata(ZenRule rule) { + Parcel p = Parcel.obtain(); + try { + rule.writeToParcel(p, 0); + p.setDataPosition(0); + ZenRule copy = new ZenRule(p); + copy.creationTime = 0; + copy.userModifiedFields = 0; + copy.zenPolicyUserModifiedFields = 0; + copy.zenDeviceEffectsUserModifiedFields = 0; + copy.lastActivation = null; + return copy; + } finally { + p.recycle(); + } + } private ZenRule expectedImplicitRule(String ownerPkg, int zenMode, ZenPolicy policy, @Nullable Boolean conditionActive) { @@ -7693,6 +7923,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { return mNowMillis; } + private void setNow(Instant instant) { + mNowMillis = instant.toEpochMilli(); + } + private void setNowMillis(long millis) { mNowMillis = millis; } diff --git a/services/tests/wmtests/res/values/styles.xml b/services/tests/wmtests/res/values/styles.xml index 6857ff99e9b8..6ded2b557bcc 100644 --- a/services/tests/wmtests/res/values/styles.xml +++ b/services/tests/wmtests/res/values/styles.xml @@ -21,4 +21,14 @@ <item name="android:windowIsTranslucent">true</item> <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> </style> + + <style name="ActivityWindowStyleTest"> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowIsFloating">true</item> + <item name="android:windowShowWallpaper">true</item> + <item name="android:windowNoDisplay">true</item> + <item name="android:windowDisablePreview">true</item> + <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> + <item name="android:windowSplashScreenBehavior">icon_preferred</item> + </style> </resources> diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java index 8e2cea7a8c78..6d8a48799112 100644 --- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java @@ -244,9 +244,6 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { {"Meta + L -> Lock Homescreen", new int[]{META_KEY, KeyEvent.KEYCODE_L}, KeyGestureEvent.KEY_GESTURE_TYPE_LOCK_SCREEN, KeyEvent.KEYCODE_L, META_ON}, - {"Meta + Ctrl + N -> Open Notes", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_N}, - KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES, KeyEvent.KEYCODE_N, - META_ON | CTRL_ON}, {"Meta + Ctrl + DPAD_DOWN -> Enter desktop mode", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_DOWN}, KeyGestureEvent.KEY_GESTURE_TYPE_DESKTOP_MODE, diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java index 32a3b7f2c9cc..22c86eb3a9b8 100644 --- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTests.java @@ -272,6 +272,19 @@ public class PhoneWindowManagerTests { } @Test + public void powerPress_withoutDreamManagerInternal_doesNotCrash() { + when(mDisplayPolicy.isAwake()).thenReturn(true); + mDreamManagerInternal = null; + initPhoneWindowManager(); + + // Power button pressed. + int eventTime = 0; + mPhoneWindowManager.powerPress(eventTime, 1, 0); + + // verify no crash + } + + @Test public void powerPress_hubOrDreamOrSleep_hubAvailableLocks() { when(mDisplayPolicy.isAwake()).thenReturn(true); mContext.getTestablePermissions().setPermission(android.Manifest.permission.DEVICE_POWER, @@ -352,5 +365,10 @@ public class PhoneWindowManagerTests { WindowWakeUpPolicy getWindowWakeUpPolicy() { return mock(WindowWakeUpPolicy.class); } + + @Override + DreamManagerInternal getDreamManagerInternal() { + return mDreamManagerInternal; + } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 9e7575f1c644..f5bda9f2b9e3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -104,7 +104,6 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase { .setTask(mTrampolineActivity.getTask()) .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TopActivity")) .build(); - mTopActivity.mDisplayContent.mOpeningApps.add(mTopActivity); mTransition = new Transition(TRANSIT_OPEN, 0 /* flags */, mTopActivity.mTransitionController, createTestBLASTSyncEngine()); mTransition.mParticipants.add(mTopActivity); @@ -485,7 +484,6 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase { @Test public void testActivityDrawnWithoutTransition() { - mTopActivity.mDisplayContent.mOpeningApps.remove(mTopActivity); mTransition.mParticipants.remove(mTopActivity); onIntentStarted(mTopActivity.intent); notifyAndVerifyActivityLaunched(mTopActivity); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index bb296148dad1..301a7544227f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -56,8 +56,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; import static android.view.WindowManager.TRANSIT_PIP; import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; @@ -921,12 +919,6 @@ public class ActivityRecordTests extends WindowTestsBase { // animation and AR#takeSceneTransitionInfo also clear the AR#mPendingOptions assertNull(activity.takeSceneTransitionInfo()); assertNull(activity.getOptions()); - - final AppTransition appTransition = activity.mDisplayContent.mAppTransition; - spyOn(appTransition); - activity.applyOptionsAnimation(); - - verify(appTransition).overridePendingAppTransitionRemote(any()); } @Test @@ -992,6 +984,27 @@ public class ActivityRecordTests extends WindowTestsBase { assertEquals(persistentSavedState, activity.getPersistentSavedState()); } + @Test + public void testReadWindowStyle() { + final ActivityRecord activity = new ActivityBuilder(mAtm).setActivityTheme( + com.android.frameworks.wmtests.R.style.ActivityWindowStyleTest).build(); + assertTrue(activity.isNoDisplay()); + assertTrue("Fill parent because showWallpaper", activity.mStyleFillsParent); + + final ActivityRecord.WindowStyle style = mAtm.getWindowStyle( + activity.packageName, activity.info.theme, activity.mUserId); + assertNotNull(style); + assertTrue(style.isTranslucent()); + assertTrue(style.isFloating()); + assertTrue(style.showWallpaper()); + assertTrue(style.noDisplay()); + assertTrue(style.disablePreview()); + assertTrue(style.optOutEdgeToEdge()); + assertEquals(1 /* icon_preferred */, style.mSplashScreenBehavior); + assertEquals(style.noDisplay(), mAtm.mInternal.isNoDisplay(activity.packageName, + activity.info.theme, activity.mUserId)); + } + /** * Verify that activity finish request is not performed if activity is finishing or is in * incorrect state. @@ -1169,7 +1182,6 @@ public class ActivityRecordTests extends WindowTestsBase { FINISH_RESULT_REQUESTED, activity.finishIfPossible("test", false /* oomAdj */)); assertEquals(PAUSING, activity.getState()); verify(activity).setVisibility(eq(false)); - verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE)); } /** @@ -1216,7 +1228,6 @@ public class ActivityRecordTests extends WindowTestsBase { activity.finishIfPossible("test", false /* oomAdj */); verify(activity).setVisibility(eq(false)); - verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE)); verify(activity.mDisplayContent, never()).executeAppTransition(); } @@ -1233,7 +1244,6 @@ public class ActivityRecordTests extends WindowTestsBase { activity.finishIfPossible("test", false /* oomAdj */); verify(activity, atLeast(1)).setVisibility(eq(false)); - verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE)); verify(activity.mDisplayContent).executeAppTransition(); } @@ -1254,7 +1264,6 @@ public class ActivityRecordTests extends WindowTestsBase { activity.finishIfPossible("test", false /* oomAdj */); - verify(activity.mDisplayContent, never()).prepareAppTransition(eq(TRANSIT_CLOSE)); assertFalse(activity.inTransition()); // finishIfPossible -> completeFinishing -> addToFinishingAndWaitForIdle @@ -2636,10 +2645,6 @@ public class ActivityRecordTests extends WindowTestsBase { @Presubmit public void testGetOrientation() { mDisplayContent.setIgnoreOrientationRequest(false); - // ActivityBuilder will resume top activities and cause the activity been added into - // opening apps list. Since this test is focus on the effect of visible on getting - // orientation, we skip app transition to avoid interference. - doNothing().when(mDisplayContent).prepareAppTransition(anyInt()); final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); activity.setVisible(true); @@ -2904,7 +2909,6 @@ public class ActivityRecordTests extends WindowTestsBase { sources.add(activity2); doReturn(true).when(activity2).okToAnimate(); doReturn(true).when(activity2).isAnimating(); - assertTrue(activity2.applyAnimation(null, TRANSIT_OLD_ACTIVITY_OPEN, true, false, sources)); } @Test public void testTrackingStartingWindowThroughTrampoline() { @@ -3326,16 +3330,13 @@ public class ActivityRecordTests extends WindowTestsBase { makeWindowVisibleAndDrawn(app); // Put the activity in close transition. - mDisplayContent.mOpeningApps.clear(); - mDisplayContent.mClosingApps.add(app.mActivityRecord); - mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); + requestTransition(app.mActivityRecord, WindowManager.TRANSIT_CLOSE); // Remove window during transition, so it is requested to hide, but won't be committed until // the transition is finished. app.mActivityRecord.onRemovedFromDisplay(); app.mActivityRecord.prepareSurfaces(); - assertTrue(mDisplayContent.mClosingApps.contains(app.mActivityRecord)); assertFalse(app.mActivityRecord.isVisibleRequested()); assertTrue(app.mActivityRecord.isVisible()); assertTrue(app.mActivityRecord.isSurfaceShowing()); @@ -3353,11 +3354,6 @@ public class ActivityRecordTests extends WindowTestsBase { makeWindowVisibleAndDrawn(app); app.mActivityRecord.prepareSurfaces(); - // Put the activity in close transition. - mDisplayContent.mOpeningApps.clear(); - mDisplayContent.mClosingApps.add(app.mActivityRecord); - mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); - // Commit visibility before start transition. app.mActivityRecord.commitVisibility(false, false); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java index 018ea58e7120..d016e735f0c7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java @@ -151,6 +151,10 @@ class AppCompatActivityRobot { doReturn(taskBounds).when(mTaskStack.top()).getBounds(); } + void configureTaskAppBounds(@NonNull Rect appBounds) { + mTaskStack.top().getWindowConfiguration().setAppBounds(appBounds); + } + void configureTopActivityBounds(@NonNull Rect activityBounds) { doReturn(activityBounds).when(mActivityStack.top()).getBounds(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java index 0c310324ce67..2603d787ae37 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java @@ -16,7 +16,9 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; @@ -27,6 +29,7 @@ import static org.junit.Assert.assertNull; import static org.mockito.Mockito.mock; import android.graphics.Rect; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsState; @@ -40,6 +43,7 @@ import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; import com.android.internal.R; +import com.android.window.flags.Flags; import org.junit.Test; import org.junit.runner.RunWith; @@ -225,6 +229,53 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase { }); } + @Test + @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS) + public void testGetRoundedCornersRadius_letterboxBoundsMatchHeightInFreeform_notRounded() { + runTestScenario((robot) -> { + robot.conf().setLetterboxActivityCornersRadius(15); + robot.configureWindowState(); + robot.activity().createActivityWithComponent(); + robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false); + robot.activity().setTopActivityVisible(/* isVisible */ true); + robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true); + robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true); + robot.resources().configureGetDimensionPixelSize(R.dimen.taskbar_frame_height, 20); + + robot.activity().setTaskWindowingMode(WINDOWING_MODE_FREEFORM); + final Rect appBounds = new Rect(0, 0, 100, 500); + robot.configureWindowStateFrame(appBounds); + robot.activity().configureTaskAppBounds(appBounds); + + robot.startLetterbox(); + + robot.checkWindowStateRoundedCornersRadius(/* expected */ 0); + }); + } + + @Test + @EnableFlags(Flags.FLAG_EXCLUDE_CAPTION_FROM_APP_BOUNDS) + public void testGetRoundedCornersRadius_letterboxBoundsNotMatchHeightInFreeform_rounded() { + runTestScenario((robot) -> { + robot.conf().setLetterboxActivityCornersRadius(15); + robot.configureWindowState(); + robot.activity().createActivityWithComponent(); + robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false); + robot.activity().setTopActivityVisible(/* isVisible */ true); + robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true); + robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true); + robot.resources().configureGetDimensionPixelSize(R.dimen.taskbar_frame_height, 20); + + robot.activity().setTaskWindowingMode(WINDOWING_MODE_FREEFORM); + robot.configureWindowStateFrame(new Rect(0, 0, 500, 200)); + robot.activity().configureTaskAppBounds(new Rect(0, 0, 500, 500)); + + robot.startLetterbox(); + + robot.checkWindowStateRoundedCornersRadius(/* expected */ 15); + }); + } + /** * Runs a test scenario providing a Robot. */ @@ -265,6 +316,10 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase { spyOn(getTransparentPolicy()); } + void startLetterbox() { + getAppCompatLetterboxPolicy().start(mWindowState); + } + void configureWindowStateWithTaskBar(boolean hasInsetsRoundedCorners) { configureWindowState(/* withTaskBar */ true, hasInsetsRoundedCorners); } @@ -273,6 +328,10 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase { configureWindowState(/* withTaskBar */ false, /* hasInsetsRoundedCorners */ false); } + void configureWindowStateFrame(@NonNull Rect frame) { + doReturn(frame).when(mWindowState).getFrame(); + } + void configureInsetsRoundedCorners(@NonNull RoundedCorners roundedCorners) { mInsetsState.setRoundedCorners(roundedCorners); } @@ -290,6 +349,7 @@ public class AppCompatLetterboxPolicyTest extends WindowTestsBase { } mWindowState.mInvGlobalScale = 1f; final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(); + attrs.type = TYPE_BASE_APPLICATION; doReturn(mInsetsState).when(mWindowState).getInsetsState(); doReturn(attrs).when(mWindowState).getAttrs(); doReturn(true).when(mWindowState).isDrawn(); diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index fbb123e25b29..e08197155f03 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -294,6 +294,14 @@ public class BackNavigationControllerTests extends WindowTestsBase { backNavigationInfo = startBackNavigation(); assertThat(typeToString(backNavigationInfo.getType())) .isEqualTo(typeToString(BackNavigationInfo.TYPE_CROSS_ACTIVITY)); + + // reset drawing status, test previous activity has no process. + backNavigationInfo.onBackNavigationFinished(false); + mBackNavigationController.clearBackAnimations(true); + doReturn(false).when(testCase.recordBack).hasProcess(); + backNavigationInfo = startBackNavigation(); + assertThat(typeToString(backNavigationInfo.getType())) + .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java index e6c3fb369b91..1e91bedb5c18 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; @@ -30,7 +28,6 @@ import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; -import android.provider.Settings; import android.window.DesktopModeFlags; import androidx.test.filters.SmallTest; @@ -74,14 +71,12 @@ public class DesktopModeHelperTest { doReturn(mContext.getContentResolver()).when(mMockContext).getContentResolver(); resetDesktopModeFlagsCache(); resetEnforceDeviceRestriction(); - resetFlagOverride(); } @After public void tearDown() throws Exception { resetDesktopModeFlagsCache(); resetEnforceDeviceRestriction(); - resetFlagOverride(); } @DisableFlags({Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE, @@ -167,7 +162,8 @@ public class DesktopModeHelperTest { @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION) @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) @Test - public void canEnterDesktopMode_DWFlagEnabled_configDevOptionOn_flagOverrideOn_returnsTrue() { + public void canEnterDesktopMode_DWFlagEnabled_configDevOptionOn_flagOverrideOn_returnsTrue() + throws Exception { doReturn(true).when(mMockResources).getBoolean( eq(R.bool.config_isDesktopModeDevOptionSupported) ); @@ -246,13 +242,10 @@ public class DesktopModeHelperTest { cachedToggleOverride.set(/* obj= */ null, /* value= */ null); } - private void resetFlagOverride() { - Settings.Global.putString(mContext.getContentResolver(), - DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, null); - } - - private void setFlagOverride(DesktopModeFlags.ToggleOverride override) { - Settings.Global.putInt(mContext.getContentResolver(), - DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, override.getSetting()); + private void setFlagOverride(DesktopModeFlags.ToggleOverride override) throws Exception { + Field cachedToggleOverride = DesktopModeFlags.class.getDeclaredField( + "sCachedToggleOverride"); + cachedToggleOverride.setAccessible(true); + cachedToggleOverride.set(/* obj= */ null, /* value= */ override); } }
\ No newline at end of file diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 6e109a8d4eaf..181853066f7b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -63,9 +63,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; @@ -1742,8 +1739,6 @@ public class DisplayContentTests extends WindowTestsBase { public void testFixedRotationWithPip() { final DisplayContent displayContent = mDefaultDisplay; displayContent.setIgnoreOrientationRequest(false); - // Unblock the condition in PinnedTaskController#continueOrientationChangeIfNeeded. - doNothing().when(displayContent).prepareAppTransition(anyInt()); // Make resume-top really update the activity state. setBooted(mAtm); clearInvocations(mWm); @@ -1800,8 +1795,7 @@ public class DisplayContentTests extends WindowTestsBase { final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true).build(); app.setVisible(false); app.setState(ActivityRecord.State.RESUMED, "test"); - mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_OPEN); - mDisplayContent.mOpeningApps.add(app); + requestTransition(app, WindowManager.TRANSIT_OPEN); final int newOrientation = getRotatedOrientation(mDisplayContent); app.setRequestedOrientation(newOrientation); @@ -2374,33 +2368,6 @@ public class DisplayContentTests extends WindowTestsBase { @SetupWindows(addWindows = W_INPUT_METHOD) @Test - public void testShowImeScreenshot() { - final Task rootTask = createTask(mDisplayContent); - final Task task = createTaskInRootTask(rootTask, 0 /* userId */); - final ActivityRecord activity = createActivityRecord(mDisplayContent, task); - final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setWindowToken( - activity).build(); - task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE); - doReturn(true).when(task).okToAnimate(); - ArrayList<WindowContainer> sources = new ArrayList<>(); - sources.add(activity); - - mDisplayContent.setImeLayeringTarget(win); - spyOn(mDisplayContent); - - // Expecting the IME screenshot only be attached when performing task closing transition. - task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */, - false /* isVoiceInteraction */, sources); - verify(mDisplayContent).showImeScreenshot(); - - clearInvocations(mDisplayContent); - activity.applyAnimation(null, TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE, false /* enter */, - false /* isVoiceInteraction */, sources); - verify(mDisplayContent, never()).showImeScreenshot(); - } - - @SetupWindows(addWindows = W_INPUT_METHOD) - @Test public void testShowImeScreenshot_removeCurSnapshotBeforeCreateNext() { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); @@ -2428,32 +2395,6 @@ public class DisplayContentTests extends WindowTestsBase { @UseTestDisplay(addWindows = {W_INPUT_METHOD}) @Test - public void testRemoveImeScreenshot_whenTargetSurfaceWasInvisible() { - final Task rootTask = createTask(mDisplayContent); - final Task task = createTaskInRootTask(rootTask, 0 /* userId */); - final ActivityRecord activity = createActivityRecord(mDisplayContent, task); - final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setWindowToken( - activity).build(); - win.onSurfaceShownChanged(true); - makeWindowVisible(win, mDisplayContent.mInputMethodWindow); - task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE); - doReturn(true).when(task).okToAnimate(); - ArrayList<WindowContainer> sources = new ArrayList<>(); - sources.add(activity); - - mDisplayContent.setImeLayeringTarget(win); - mDisplayContent.setImeInputTarget(win); - mDisplayContent.getInsetsStateController().getImeSourceProvider().setImeShowing(true); - task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */, - false /* isVoiceInteraction */, sources); - assertNotNull(mDisplayContent.mImeScreenshot); - - win.onSurfaceShownChanged(false); - assertNull(mDisplayContent.mImeScreenshot); - } - - @UseTestDisplay(addWindows = {W_INPUT_METHOD}) - @Test public void testRemoveImeScreenshot_whenWindowRemoveImmediately() { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); diff --git a/services/tests/wmtests/src/com/android/server/wm/PresentationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/PresentationControllerTests.java index db90c28ec7df..2d4101e40615 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PresentationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/PresentationControllerTests.java @@ -17,17 +17,21 @@ package com.android.server.wm; import static android.view.Display.FLAG_PRESENTATION; +import static android.view.WindowManager.TRANSIT_CLOSE; +import static android.view.WindowManager.TRANSIT_OPEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.window.flags.Flags.FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; +import android.annotation.NonNull; import android.graphics.Rect; import android.os.UserHandle; -import android.os.UserManager; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.DisplayInfo; @@ -41,6 +45,7 @@ import android.view.WindowManagerGlobal; import androidx.test.filters.SmallTest; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -53,35 +58,100 @@ import org.junit.runner.RunWith; @RunWith(WindowTestRunner.class) public class PresentationControllerTests extends WindowTestsBase { + TestTransitionPlayer mPlayer; + + @Before + public void setUp() { + mPlayer = registerTestTransitionPlayer(); + } + @EnableFlags(FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS) @Test - public void testPresentationHidesActivitiesBehind() { - final DisplayInfo displayInfo = new DisplayInfo(); - displayInfo.copyFrom(mDisplayInfo); - displayInfo.flags = FLAG_PRESENTATION; - final DisplayContent dc = createNewDisplay(displayInfo); - final int displayId = dc.getDisplayId(); - doReturn(dc).when(mWm.mRoot).getDisplayContentOrCreate(displayId); + public void testPresentationShowAndHide() { + final DisplayContent dc = createPresentationDisplay(); final ActivityRecord activity = createActivityRecord(createTask(dc)); assertTrue(activity.isVisible()); - doReturn(true).when(() -> UserManager.isVisibleBackgroundUsersEnabled()); - final int uid = 100000; // uid for non-system user + // Add a presentation window, which requests the activity to stop. + final WindowState window = addPresentationWindow(100000, dc.mDisplayId); + assertFalse(activity.isVisibleRequested()); + assertTrue(activity.isVisible()); + final Transition addTransition = window.mTransitionController.getCollectingTransition(); + assertEquals(TRANSIT_OPEN, addTransition.mType); + assertTrue(addTransition.isInTransition(window)); + assertTrue(addTransition.isInTransition(activity)); + + // Completing the transition makes the activity invisible. + completeTransition(addTransition, /*abortSync=*/ true); + assertFalse(activity.isVisible()); + + // Remove a Presentation window, which requests the activity to be resumed back. + window.removeIfPossible(); + final Transition removeTransition = window.mTransitionController.getCollectingTransition(); + assertEquals(TRANSIT_CLOSE, removeTransition.mType); + assertTrue(removeTransition.isInTransition(window)); + assertTrue(removeTransition.isInTransition(activity)); + assertTrue(activity.isVisibleRequested()); + assertFalse(activity.isVisible()); + + // Completing the transition makes the activity visible. + completeTransition(removeTransition, /*abortSync=*/ false); + assertTrue(activity.isVisible()); + } + + @DisableFlags(FLAG_ENABLE_PRESENTATION_FOR_CONNECTED_DISPLAYS) + @Test + public void testPresentationShowAndHide_flagDisabled() { + final DisplayContent dc = createPresentationDisplay(); + final ActivityRecord activity = createActivityRecord(createTask(dc)); + assertTrue(activity.isVisible()); + + final WindowState window = addPresentationWindow(100000, dc.mDisplayId); + assertFalse(window.mTransitionController.isCollecting()); + assertTrue(activity.isVisibleRequested()); + assertTrue(activity.isVisible()); + + window.removeIfPossible(); + assertFalse(window.mTransitionController.isCollecting()); + assertTrue(activity.isVisibleRequested()); + assertTrue(activity.isVisible()); + assertFalse(window.isAttached()); + } + + private WindowState addPresentationWindow(int uid, int displayId) { final Session session = createTestSession(mAtm, 1234 /* pid */, uid); final int userId = UserHandle.getUserId(uid); - doReturn(false).when(mWm.mUmInternal).isUserVisible(eq(userId), eq(displayId)); + doReturn(true).when(mWm.mUmInternal).isUserVisible(eq(userId), eq(displayId)); final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_PRESENTATION); - final IWindow clientWindow = new TestIWindow(); - final int result = mWm.addWindow(session, clientWindow, params, View.VISIBLE, displayId, + final int res = mWm.addWindow(session, clientWindow, params, View.VISIBLE, displayId, userId, WindowInsets.Type.defaultVisible(), null, new InsetsState(), new InsetsSourceControl.Array(), new Rect(), new float[1]); - assertTrue(result >= WindowManagerGlobal.ADD_OKAY); - assertFalse(activity.isVisible()); - + assertTrue(res >= WindowManagerGlobal.ADD_OKAY); final WindowState window = mWm.windowForClientLocked(session, clientWindow, false); - window.removeImmediately(); - assertTrue(activity.isVisible()); + window.mHasSurface = true; + return window; + } + + private DisplayContent createPresentationDisplay() { + final DisplayInfo displayInfo = new DisplayInfo(); + displayInfo.copyFrom(mDisplayInfo); + displayInfo.flags = FLAG_PRESENTATION; + final DisplayContent dc = createNewDisplay(displayInfo); + final int displayId = dc.getDisplayId(); + doReturn(dc).when(mWm.mRoot).getDisplayContentOrCreate(displayId); + return dc; + } + + private void completeTransition(@NonNull Transition transition, boolean abortSync) { + final ActionChain chain = ActionChain.testFinish(transition); + if (abortSync) { + // Forcefully finishing the active sync for testing purpose. + mWm.mSyncEngine.abort(transition.getSyncId()); + } else { + transition.onTransactionReady(transition.getSyncId(), mTransaction); + } + transition.finishTransition(chain); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 2f9b321a25ec..3776b03695d5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -98,6 +98,7 @@ import com.android.server.policy.PermissionPolicyInternal; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.testutils.StubTransaction; import com.android.server.uri.UriGrantsManagerInternal; +import com.android.window.flags.Flags; import org.junit.rules.TestRule; import org.junit.runner.Description; @@ -657,6 +658,13 @@ public class SystemServicesTestRule implements TestRule { AppWarnings appWarnings = getAppWarningsLocked(); spyOn(appWarnings); doNothing().when(appWarnings).onStartActivity(any()); + + if (Flags.trackSystemUiContextBeforeWms()) { + final Context uiContext = getUiContext(); + spyOn(uiContext); + doNothing().when(uiContext).registerComponentCallbacks(any()); + doNothing().when(uiContext).unregisterComponentCallbacks(any()); + } } @Override diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 7ab55bf7e874..cc2a76dcc9f2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -189,11 +189,12 @@ public class TaskFragmentTest extends WindowTestsBase { doReturn(true).when(mTaskFragment).isVisible(); doReturn(true).when(mTaskFragment).isVisibleRequested(); + spyOn(mTaskFragment.mTransitionController); clearInvocations(mTransaction); mTaskFragment.setBounds(endBounds); // No change transition, but update the organized surface position. - verify(mTaskFragment, never()).initializeChangeTransition(any(), any()); + verify(mTaskFragment.mTransitionController, never()).collectVisibleChange(any()); verify(mTransaction).setPosition(mLeash, endBounds.left, endBounds.top); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java index ccce57a81e41..b1525cf00dc6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java @@ -30,6 +30,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; import android.content.res.Configuration; import android.graphics.Insets; import android.graphics.Rect; @@ -39,6 +40,7 @@ import android.view.DisplayCutout; import android.view.DisplayInfo; import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry; +import com.android.window.flags.Flags; class TestDisplayContent extends DisplayContent { @@ -79,6 +81,13 @@ class TestDisplayContent extends DisplayContent { WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getPermanentControlTarget()); WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getTransientControlTarget()); + if (Flags.trackSystemUiContextBeforeWms()) { + final Context uiContext = getDisplayUiContext(); + spyOn(uiContext); + doNothing().when(uiContext).registerComponentCallbacks(any()); + doNothing().when(uiContext).unregisterComponentCallbacks(any()); + } + // For devices that set the sysprop ro.bootanim.set_orientation_<display_id> // See DisplayRotation#readDefaultDisplayRotation for context. // Without that, meaning of height and width in context of the tests can be swapped if diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 2ee34d3a4b36..77ad7f7bac7f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -683,7 +683,7 @@ public class TransitionTests extends WindowTestsBase { app.onStartingWindowDrawn(); // The task appeared event should be deferred until transition ready. assertFalse(task.taskAppearedReady()); - testPlayer.onTransactionReady(app.getSyncTransaction()); + testPlayer.onTransactionReady(); assertTrue(task.taskAppearedReady()); assertTrue(playerProc.isRunningRemoteTransition()); assertTrue(controller.mRemotePlayer.reportRunning(delegateProc.getThread())); @@ -1162,7 +1162,8 @@ public class TransitionTests extends WindowTestsBase { screenDecor.updateSurfacePosition(mMockT); assertEquals(prevPos, screenDecor.mLastSurfacePosition); - final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class); + final SurfaceControl.Transaction startTransaction = mTransaction; + clearInvocations(startTransaction); final SurfaceControl.TransactionCommittedListener transactionCommittedListener = onRotationTransactionReady(player, startTransaction); @@ -1213,7 +1214,8 @@ public class TransitionTests extends WindowTestsBase { assertFalse(statusBar.mToken.inTransition()); assertTrue(app.getTask().inTransition()); - final SurfaceControl.Transaction startTransaction = mock(SurfaceControl.Transaction.class); + final SurfaceControl.Transaction startTransaction = mTransaction; + clearInvocations(startTransaction); final SurfaceControl leash = statusBar.mToken.getAnimationLeash(); doReturn(true).when(leash).isValid(); final SurfaceControl.TransactionCommittedListener transactionCommittedListener = @@ -1287,7 +1289,8 @@ public class TransitionTests extends WindowTestsBase { // Avoid DeviceStateController disturbing the test by triggering another rotation change. doReturn(false).when(mDisplayContent).updateRotationUnchecked(); - onRotationTransactionReady(player, mWm.mTransactionFactory.get()).onTransactionCommitted(); + clearInvocations(mTransaction); + onRotationTransactionReady(player, mTransaction).onTransactionCommitted(); assertEquals(ROTATION_ANIMATION_SEAMLESS, player.mLastReady.getChange( mDisplayContent.mRemoteToken.toWindowContainerToken()).getRotationAnimation()); spyOn(navBarInsetsProvider); @@ -1350,7 +1353,7 @@ public class TransitionTests extends WindowTestsBase { mDisplayContent.setFixedRotationLaunchingAppUnchecked(home); doReturn(true).when(home).hasFixedRotationTransform(any()); player.startTransition(); - player.onTransactionReady(mDisplayContent.getSyncTransaction()); + player.onTransactionReady(); final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); final RemoteDisplayChangeController displayChangeController = mDisplayContent @@ -3071,8 +3074,11 @@ public class TransitionTests extends WindowTestsBase { TestTransitionPlayer player, SurfaceControl.Transaction startTransaction) { final ArgumentCaptor<SurfaceControl.TransactionCommittedListener> listenerCaptor = ArgumentCaptor.forClass(SurfaceControl.TransactionCommittedListener.class); - player.onTransactionReady(startTransaction); - verify(startTransaction).addTransactionCommittedListener(any(), listenerCaptor.capture()); + player.onTransactionReady(); + // The startTransaction is from mWm.mTransactionFactory.get() in SyncGroup#finishNow. + // 2 times are from SyncGroup#finishNow and AsyncRotationController#setupStartTransaction. + verify(startTransaction, times(2)).addTransactionCommittedListener( + any(), listenerCaptor.capture()); return listenerCaptor.getValue(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index edffab801499..4f310de1e48b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -30,8 +30,6 @@ import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowInsets.Type.systemOverlays; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; @@ -409,17 +407,6 @@ public class WindowContainerTests extends WindowTestsBase { } @Test - public void testIsAnimating_TransitionFlag() { - final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); - final TestWindowContainer root = builder.setLayer(0).build(); - final TestWindowContainer child1 = root.addChildWindow( - builder.setWaitForTransitionStart(true)); - - assertFalse(root.isAnimating(TRANSITION)); - assertTrue(child1.isAnimating(TRANSITION)); - } - - @Test public void testIsAnimating_ParentsFlag() { final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm); final TestWindowContainer root = builder.setLayer(0).build(); @@ -1132,7 +1119,6 @@ public class WindowContainerTests extends WindowTestsBase { final ActivityRecord activity = createActivityRecord(mDisplayContent, task); final WindowState win = newWindowBuilder("win", TYPE_BASE_APPLICATION).setWindowToken( activity).build(); - task.getDisplayContent().prepareAppTransition(TRANSIT_CLOSE); spyOn(win); doReturn(true).when(task).okToAnimate(); ArrayList<WindowContainer> sources = new ArrayList<>(); @@ -1141,8 +1127,6 @@ public class WindowContainerTests extends WindowTestsBase { // Simulate the task applying the exit transition, verify the main window of the task // will be set the frozen insets state before the animation starts activity.setVisibility(false); - task.applyAnimation(null, TRANSIT_OLD_TASK_CLOSE, false /* enter */, - false /* isVoiceInteraction */, sources); verify(win).freezeInsetsState(); // Simulate the task transition finished. @@ -1655,7 +1639,7 @@ public class WindowContainerTests extends WindowTestsBase { }; TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating, - boolean isVisible, boolean waitTransitStart, Integer orientation, WindowState ws) { + boolean isVisible, Integer orientation, WindowState ws) { super(wm); mLayer = layer; @@ -1663,7 +1647,6 @@ public class WindowContainerTests extends WindowTestsBase { mIsVisible = isVisible; mFillsParent = true; mOrientation = orientation; - mWaitForTransitStart = waitTransitStart; mWindowState = ws; spyOn(mSurfaceAnimator); doReturn(mIsAnimating).when(mSurfaceAnimator).isAnimating(); @@ -1729,11 +1712,6 @@ public class WindowContainerTests extends WindowTestsBase { } @Override - boolean isWaitingForTransitionStart() { - return mWaitForTransitStart; - } - - @Override WindowState asWindowState() { return mWindowState; } @@ -1744,7 +1722,6 @@ public class WindowContainerTests extends WindowTestsBase { private int mLayer; private boolean mIsAnimating; private boolean mIsVisible; - private boolean mIsWaitTransitStart; private Integer mOrientation; private WindowState mWindowState; @@ -1782,14 +1759,9 @@ public class WindowContainerTests extends WindowTestsBase { return this; } - TestWindowContainerBuilder setWaitForTransitionStart(boolean waitTransitStart) { - mIsWaitTransitStart = waitTransitStart; - return this; - } - TestWindowContainer build() { return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible, - mIsWaitTransitStart, mOrientation, mWindowState); + mOrientation, mWindowState); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index 1dfb20a41816..d228970e0371 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED; +import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION; import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; @@ -33,9 +34,11 @@ import static com.android.server.wm.ActivityRecord.State.RESUMED; import static com.android.server.wm.ActivityRecord.State.STARTED; import static com.android.server.wm.ActivityRecord.State.STOPPED; import static com.android.server.wm.ActivityRecord.State.STOPPING; +import static com.android.server.wm.ConfigurationContainer.applySizeOverrideIfNeeded; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -58,6 +61,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.LocaleList; import android.os.RemoteException; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import org.junit.Before; @@ -453,6 +457,56 @@ public class WindowProcessControllerTests extends WindowTestsBase { assertEquals(topDisplayArea, mWpc.getTopActivityDisplayArea()); } + @Test + @EnableFlags(com.android.window.flags.Flags.FLAG_INSETS_DECOUPLED_CONFIGURATION) + public void testOverrideConfigurationApplied() { + final DisplayContent displayContent = new TestDisplayContent.Builder(mAtm, 1000, 1500) + .setSystemDecorations(true).setDensityDpi(160).build(); + final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); + // Setup the decor insets info. + final DisplayPolicy.DecorInsets.Info decorInsetsInfo = new DisplayPolicy.DecorInsets.Info(); + final Rect emptyRect = new Rect(); + decorInsetsInfo.mNonDecorInsets.set(emptyRect); + decorInsetsInfo.mConfigInsets.set(emptyRect); + decorInsetsInfo.mOverrideConfigInsets.set(new Rect(0, 100, 0, 200)); + decorInsetsInfo.mOverrideNonDecorInsets.set(new Rect(0, 0, 0, 200)); + decorInsetsInfo.mNonDecorFrame.set(new Rect(0, 0, 1000, 1500)); + decorInsetsInfo.mConfigFrame.set(new Rect(0, 0, 1000, 1500)); + decorInsetsInfo.mOverrideConfigFrame.set(new Rect(0, 100, 1000, 1300)); + decorInsetsInfo.mOverrideNonDecorFrame.set(new Rect(0, 0, 1000, 1300)); + doReturn(decorInsetsInfo).when(displayPolicy) + .getDecorInsetsInfo(anyInt(), anyInt(), anyInt()); + + final Configuration newParentConfig = displayContent.getConfiguration(); + final Configuration resolvedConfig = new Configuration(); + + // Mock the app info to not enforce the decoupled configuration to apply the override. + final ApplicationInfo appInfo = mock(ApplicationInfo.class); + doReturn(false).when(appInfo) + .isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED); + doReturn(false).when(appInfo) + .isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION); + + // No value should be set before override. + assertNull(resolvedConfig.windowConfiguration.getAppBounds()); + applySizeOverrideIfNeeded( + displayContent, + appInfo, + newParentConfig, + resolvedConfig, + false /* optsOutEdgeToEdge */, + false /* hasFixedRotationTransform */, + false /* hasCompatDisplayInsets */, + null /* task */); + + // Assert the override config insets are applied. + // Status bars, and all non-decor insets should be deducted for the config screen size. + assertEquals(1200, resolvedConfig.screenHeightDp); + // Only the non-decor insets should be deducted for the app bounds. + assertNotNull(resolvedConfig.windowConfiguration.getAppBounds()); + assertEquals(1300, resolvedConfig.windowConfiguration.getAppBounds().height()); + } + private TestDisplayContent createTestDisplayContentInContainer() { return new TestDisplayContent.Builder(mAtm, 1000, 1500).build(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 7f9e591ca5e3..c6416850c464 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -861,11 +861,9 @@ public class WindowTestsBase extends SystemServiceTestsBase { /** Creates a {@link DisplayContent} and adds it to the system. */ private DisplayContent createNewDisplay(DisplayInfo info, @DisplayImePolicy int imePolicy, @Nullable SettingsEntry overrideSettings) { - final DisplayContent display = - new TestDisplayContent.Builder(mAtm, info) - .setOverrideSettings(overrideSettings) - .build(); - final DisplayContent dc = display.mDisplayContent; + final DisplayContent dc = new TestDisplayContent.Builder(mAtm, info) + .setOverrideSettings(overrideSettings) + .build(); // this display can show IME. dc.mWmService.mDisplayWindowSettings.setDisplayImePolicy(dc, imePolicy); return dc; @@ -2161,13 +2159,14 @@ public class WindowTestsBase extends SystemServiceTestsBase { mOrganizer.startTransition(mLastTransit.getToken(), null); } - void onTransactionReady(SurfaceControl.Transaction t) { - mLastTransit.onTransactionReady(mLastTransit.getSyncId(), t); + void onTransactionReady() { + // SyncGroup#finishNow -> Transition#onTransactionReady. + mController.mSyncEngine.abort(mLastTransit.getSyncId()); } void start() { startTransition(); - onTransactionReady(mock(SurfaceControl.Transaction.class)); + onTransactionReady(); } public void finish() { diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/WindowStyleCacheTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/WindowStyleCacheTest.java new file mode 100644 index 000000000000..57a340129456 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/utils/WindowStyleCacheTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.utils; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; + +import android.content.Context; +import android.content.res.TypedArray; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; + +import com.android.internal.policy.AttributeCache; + +import org.junit.Test; + +/** + * Build/Install/Run: + * atest WmTests:WindowStyleCacheTest + */ +@SmallTest +@Presubmit +public class WindowStyleCacheTest { + + @Test + public void testCache() { + final Context context = getInstrumentation().getContext(); + AttributeCache.init(context); + final WindowStyleCache<TestStyle> cache = new WindowStyleCache<>(TestStyle::new); + final String packageName = context.getPackageName(); + final int theme = com.android.frameworks.wmtests.R.style.ActivityWindowStyleTest; + final int userId = context.getUserId(); + final TestStyle style = cache.get(packageName, theme, userId); + assertNotNull(style); + assertSame(style, cache.get(packageName, theme, userId)); + + cache.invalidatePackage(packageName); + assertNotSame(style, cache.get(packageName, theme, userId)); + } + + private static class TestStyle { + TestStyle(TypedArray array) { + } + } +} diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index ec4f7e1ea4ba..4395b76d91cc 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -52,6 +52,7 @@ import android.os.Bundle; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.service.usb.UsbServiceDumpProto; @@ -694,6 +695,11 @@ public class UsbService extends IUsbManager.Stub { return (getCurrentFunctions() & UsbManager.usbFunctionsFromString(function)) != 0; } + @Override + public boolean isUvcGadgetSupportEnabled() { + return SystemProperties.getBoolean("ro.usb.uvc.enabled", false); + } + @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_USB) @Override public long getCurrentFunctions() { diff --git a/startop/OWNERS b/startop/OWNERS index 11d5ad0f000a..3414a7469ac2 100644 --- a/startop/OWNERS +++ b/startop/OWNERS @@ -1,2 +1 @@ include platform/art:/OWNERS -keunyoung@google.com diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 1a932859b750..58833e8f8141 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -9786,7 +9786,6 @@ public class CarrierConfigManager { * <p> * This config is empty by default. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE = "carrier_supported_satellite_services_per_provider_bundle"; @@ -9826,7 +9825,6 @@ public class CarrierConfigManager { * * The default value is false. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_SATELLITE_ATTACH_SUPPORTED_BOOL = "satellite_attach_supported_bool"; @@ -9848,7 +9846,6 @@ public class CarrierConfigManager { * <p> * The default value is 180 seconds. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT = "satellite_connection_hysteresis_sec_int"; @@ -9863,7 +9860,6 @@ public class CarrierConfigManager { * See SignalStrength#MAX_LTE_RSRP and SignalStrength#MIN_LTE_RSRP. Any signal level outside * these boundaries is considered invalid. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_NTN_LTE_RSRP_THRESHOLDS_INT_ARRAY = "ntn_lte_rsrp_thresholds_int_array"; @@ -9883,7 +9879,6 @@ public class CarrierConfigManager { * This key is considered invalid if the format is violated. If the key is invalid or * not configured, a default value set will apply. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_NTN_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "ntn_lte_rsrq_thresholds_int_array"; @@ -9901,7 +9896,6 @@ public class CarrierConfigManager { * This key is considered invalid if the format is violated. If the key is invalid or * not configured, a default value set will apply. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_NTN_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "ntn_lte_rssnr_thresholds_int_array"; @@ -9926,7 +9920,6 @@ public class CarrierConfigManager { * If the key is invalid or not configured, a default value (RSRP = 1 << 0) will apply. * */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT = "parameters_used_for_ntn_lte_signal_bar_int"; @@ -10018,7 +10011,6 @@ public class CarrierConfigManager { * * The default value is 7 days. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_SATELLITE_ENTITLEMENT_STATUS_REFRESH_DAYS_INT = "satellite_entitlement_status_refresh_days_int"; @@ -10029,7 +10021,6 @@ public class CarrierConfigManager { * * The default value is false. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final String KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL = "satellite_entitlement_supported_bool"; diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index 0c324e6061cb..7de0a2a8edb5 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -209,7 +209,6 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * MMS service */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final int SERVICE_TYPE_MMS = 6; /** @hide */ @@ -713,7 +712,6 @@ public final class NetworkRegistrationInfo implements Parcelable { * * @return {@code true} if network is a non-terrestrial network else {@code false}. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public boolean isNonTerrestrialNetwork() { return mIsNonTerrestrialNetwork; } @@ -1198,7 +1196,6 @@ public final class NetworkRegistrationInfo implements Parcelable { * else {@code false}. * @return The builder. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public @NonNull Builder setIsNonTerrestrialNetwork(boolean isNonTerrestrialNetwork) { mIsNonTerrestrialNetwork = isNonTerrestrialNetwork; return this; diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 127bbff01575..35dd8b240e13 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -16,7 +16,6 @@ package android.telephony; -import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -36,7 +35,6 @@ import android.telephony.NetworkRegistrationInfo.Domain; import android.telephony.NetworkRegistrationInfo.NRState; import android.text.TextUtils; -import com.android.internal.telephony.flags.Flags; import com.android.telephony.Rlog; import java.lang.annotation.Retention; @@ -2262,7 +2260,6 @@ public class ServiceState implements Parcelable { * * @return {@code true} if device is connected to a non-terrestrial network else {@code false}. */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public boolean isUsingNonTerrestrialNetwork() { synchronized (mNetworkRegistrationInfos) { for (NetworkRegistrationInfo nri : mNetworkRegistrationInfos) { diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java index bb4ce6e787de..4411873b40dd 100644 --- a/telephony/java/android/telephony/TelephonyDisplayInfo.java +++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java @@ -16,15 +16,12 @@ package android.telephony; -import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; import android.telephony.Annotation.OverrideNetworkType; -import com.android.internal.telephony.flags.Flags; - import java.util.Objects; /** @@ -97,10 +94,8 @@ public final class TelephonyDisplayInfo implements Parcelable { private final boolean mIsRoaming; - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) private final boolean mIsNtn; - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) private final boolean mIsSatelliteConstrainedData; /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 504605d0a1a2..41569deeddb5 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -7080,7 +7080,8 @@ public class TelephonyManager { */ @Deprecated public boolean isVoiceCapable() { - return hasCapability(PackageManager.FEATURE_TELEPHONY_CALLING, + if (mContext == null) return true; + return mContext.getResources().getBoolean( com.android.internal.R.bool.config_voice_capable); } @@ -7104,7 +7105,8 @@ public class TelephonyManager { * @see SubscriptionInfo#getServiceCapabilities() */ public boolean isDeviceVoiceCapable() { - return isVoiceCapable(); + return hasCapability(PackageManager.FEATURE_TELEPHONY_CALLING, + com.android.internal.R.bool.config_voice_capable); } /** diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 22624e22d534..7eb1eb9475d3 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -126,7 +126,6 @@ public class ApnSetting implements Parcelable { /** APN type for ENTERPRISE. */ public static final int TYPE_ENTERPRISE = ApnTypes.ENTERPRISE; /** APN type for RCS (Rich Communication Services). */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final int TYPE_RCS = ApnTypes.RCS; /** APN type for OEM_PAID networks (Automotive PANS) */ @FlaggedApi(Flags.FLAG_OEM_PAID_PRIVATE) @@ -379,7 +378,6 @@ public class ApnSetting implements Parcelable { * modem components or carriers. Non-system apps should use the integer variants instead. * @hide */ - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @SystemApi public static final String TYPE_RCS_STRING = "rcs"; diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java index 100690dcbb65..13096548a8ba 100644 --- a/telephony/java/android/telephony/satellite/SatelliteManager.java +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -755,7 +755,6 @@ public final class SatelliteManager { * @hide */ @SystemApi - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final int EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911 = 2; /** @@ -1574,7 +1573,6 @@ public final class SatelliteManager { * @hide */ @SystemApi - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_GEOLOCATION = 1; /** @@ -1584,7 +1582,6 @@ public final class SatelliteManager { * @hide */ @SystemApi - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public static final int SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT = 2; /** @hide */ @@ -2757,7 +2754,6 @@ public final class SatelliteManager { */ @SystemApi @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public void requestAttachEnabledForCarrier(int subId, boolean enableSatellite, @NonNull @CallbackExecutor Executor executor, @SatelliteResult @NonNull Consumer<Integer> resultListener) { @@ -2794,7 +2790,6 @@ public final class SatelliteManager { */ @SystemApi @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public void requestIsAttachEnabledForCarrier(int subId, @NonNull @CallbackExecutor Executor executor, @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { @@ -2822,7 +2817,6 @@ public final class SatelliteManager { */ @SystemApi @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public void addAttachRestrictionForCarrier(int subId, @SatelliteCommunicationRestrictionReason int reason, @NonNull @CallbackExecutor Executor executor, @@ -2870,7 +2864,6 @@ public final class SatelliteManager { */ @SystemApi @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) public void removeAttachRestrictionForCarrier(int subId, @SatelliteCommunicationRestrictionReason int reason, @NonNull @CallbackExecutor Executor executor, @@ -2918,7 +2911,6 @@ public final class SatelliteManager { @SystemApi @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) @SatelliteCommunicationRestrictionReason - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @NonNull public Set<Integer> getAttachRestrictionReasonsForCarrier(int subId) { if (!SubscriptionManager.isValidSubscriptionId(subId)) { throw new IllegalArgumentException("Invalid subscription ID"); @@ -3317,7 +3309,6 @@ public final class SatelliteManager { */ @SystemApi @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) - @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) @NonNull public List<String> getSatellitePlmnsForCarrier(int subId) { if (!SubscriptionManager.isValidSubscriptionId(subId)) { throw new IllegalArgumentException("Invalid subscription ID"); diff --git a/tests/AppJankTest/res/values/strings.xml b/tests/AppJankTest/res/values/strings.xml new file mode 100644 index 000000000000..ab2d18fa9d53 --- /dev/null +++ b/tests/AppJankTest/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> + <string name="continue_test">Continue Test</string> +</resources>
\ No newline at end of file diff --git a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java index fe9f63615757..3498974b348e 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java +++ b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java @@ -209,7 +209,8 @@ public class IntegrationTests { JankTrackerActivity.class); resumeJankTracker.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); mEmptyActivity.startActivity(resumeJankTracker); - mDevice.wait(Until.findObject(By.text("Edit Text")), WAIT_FOR_TIMEOUT_MS); + mDevice.wait(Until.findObject(By.text(mEmptyActivity.getString(R.string.continue_test))), + WAIT_FOR_TIMEOUT_MS); assertTrue(jankTracker.shouldTrack()); } diff --git a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java index 80ab6ad3e587..686758200853 100644 --- a/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java +++ b/tests/AppJankTest/src/android/app/jank/tests/JankTrackerActivity.java @@ -18,15 +18,41 @@ package android.app.jank.tests; import android.app.Activity; import android.os.Bundle; +import android.widget.EditText; public class JankTrackerActivity extends Activity { + private static final int CONTINUE_TEST_DELAY_MS = 4000; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.jank_tracker_activity_layout); } + + /** + * In IntegrationTests#jankTrackingResumed_whenActivityBecomesVisibleAgain this activity is + * placed into the background and then resumed via an intent. The test waits until the + * `continue_test` string is visible on the screen before validating that Jank tracking has + * resumed. + * + * <p>The 4 second delay allows JankTracker to re-register its callbacks and start receiving + * JankData before the test proceeds. + */ + @Override + protected void onResume() { + super.onResume(); + getActivityThread().getHandler().postDelayed(new Runnable() { + @Override + public void run() { + EditText editTextView = findViewById(R.id.edit_text); + if (editTextView != null) { + editTextView.setText(R.string.continue_test); + } + } + }, CONTINUE_TEST_DELAY_MS); + } } diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt index a2f6f0051116..eac426700ec1 100644 --- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt +++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt @@ -160,7 +160,7 @@ class InputManagerServiceTests { testLooper = TestLooper() service = InputManagerService(object : InputManagerService.Injector( - context, testLooper.looper, uEventManager) { + context, testLooper.looper, testLooper.looper, uEventManager) { override fun getNativeService( service: InputManagerService? ): NativeInputManagerService { diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt index 88e84966634b..c666fb7e05f1 100644 --- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt @@ -207,7 +207,7 @@ class KeyGestureControllerTests { private fun setupKeyGestureController() { keyGestureController = - KeyGestureController(context, testLooper.looper, inputDataStore) + KeyGestureController(context, testLooper.looper, testLooper.looper, inputDataStore) Mockito.`when`(iInputManager.getAppLaunchBookmarks()) .thenReturn(keyGestureController.appLaunchBookmarks) keyGestureController.systemRunning() @@ -371,18 +371,6 @@ class KeyGestureControllerTests { intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( - "META + CTRL + N -> Open Notes", - intArrayOf( - KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_CTRL_LEFT, - KeyEvent.KEYCODE_N - ), - KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES, - intArrayOf(KeyEvent.KEYCODE_N), - KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) - ), - TestData( "META + S -> Take Screenshot", intArrayOf( KeyEvent.KEYCODE_META_LEFT, diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp index e294da101fb7..35564066266b 100644 --- a/tests/Internal/Android.bp +++ b/tests/Internal/Android.bp @@ -45,6 +45,7 @@ android_test { "junit", "androidx.test.rules", "platform-test-annotations", + "truth", ], manifest: "ApplicationSharedMemoryTest32/AndroidManifest.xml", test_config: "ApplicationSharedMemoryTest32/AndroidTest.xml", diff --git a/tests/Internal/src/com/android/internal/os/ApplicationSharedMemoryTest.java b/tests/Internal/src/com/android/internal/os/ApplicationSharedMemoryTest.java index d03ad5cb2877..5ce0ede3e425 100644 --- a/tests/Internal/src/com/android/internal/os/ApplicationSharedMemoryTest.java +++ b/tests/Internal/src/com/android/internal/os/ApplicationSharedMemoryTest.java @@ -16,24 +16,24 @@ package com.android.internal.os; -import java.io.IOException; +import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.junit.Before; import java.io.FileDescriptor; +import java.io.IOException; /** Tests for {@link TimeoutRecord}. */ @SmallTest @@ -77,6 +77,8 @@ public class ApplicationSharedMemoryTest { try { instance.setLatestNetworkTimeUnixEpochMillisAtZeroElapsedRealtimeMillis(17); fail("Attempted mutation in an app process should throw"); + instance.writeSystemFeaturesCache(new int[] {1, 2, 3, 4, 5}); + fail("Attempted feature mutation in an app process should throw"); } catch (Exception expected) { } } @@ -121,4 +123,56 @@ public class ApplicationSharedMemoryTest { } catch (Exception expected) { } } + + /** If system feature caching is enabled, it should be auto-written into app shared memory. */ + @Test + public void canReadSystemFeatures() throws IOException { + assumeTrue(android.content.pm.Flags.cacheSdkSystemFeatures()); + ApplicationSharedMemory instance = ApplicationSharedMemory.getInstance(); + assertThat(instance.readSystemFeaturesCache()).isNotEmpty(); + } + + @Test + public void systemFeaturesShareMemory() throws IOException { + ApplicationSharedMemory instance1 = ApplicationSharedMemory.create(); + + int[] featureVersions = new int[] {1, 2, 3, 4, 5}; + instance1.writeSystemFeaturesCache(featureVersions); + assertThat(featureVersions).isEqualTo(instance1.readSystemFeaturesCache()); + + ApplicationSharedMemory instance2 = + ApplicationSharedMemory.fromFileDescriptor( + instance1.getReadOnlyFileDescriptor(), /* mutable= */ false); + assertThat(featureVersions).isEqualTo(instance2.readSystemFeaturesCache()); + } + + @Test + public void systemFeaturesAreWriteOnce() throws IOException { + ApplicationSharedMemory instance1 = ApplicationSharedMemory.create(); + + try { + instance1.writeSystemFeaturesCache(new int[5000]); + fail("Cannot write an overly large system feature version buffer."); + } catch (IllegalArgumentException expected) { + } + + int[] featureVersions = new int[] {1, 2, 3, 4, 5}; + instance1.writeSystemFeaturesCache(featureVersions); + + int[] newFeatureVersions = new int[] {1, 2, 3, 4, 5, 6, 7}; + try { + instance1.writeSystemFeaturesCache(newFeatureVersions); + fail("Cannot update system features after first write."); + } catch (IllegalStateException expected) { + } + + ApplicationSharedMemory instance2 = + ApplicationSharedMemory.fromFileDescriptor( + instance1.getReadOnlyFileDescriptor(), /* mutable= */ false); + try { + instance2.writeSystemFeaturesCache(newFeatureVersions); + fail("Cannot update system features for read-only ashmem."); + } catch (IllegalStateException expected) { + } + } } diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp index 8be74eaccd20..44e545bac0ce 100644 --- a/tests/PackageWatchdog/Android.bp +++ b/tests/PackageWatchdog/Android.bp @@ -26,12 +26,12 @@ android_test { name: "PackageWatchdogTest", srcs: ["src/**/*.java"], static_libs: [ - "junit", - "mockito-target-extended-minus-junit4", + "PlatformProperties", + "androidx.test.rules", "flag-junit", "frameworks-base-testutils", - "androidx.test.rules", - "PlatformProperties", + "junit", + "mockito-target-extended-minus-junit4", "services.core", "services.net", "truth", @@ -49,5 +49,9 @@ android_test { "libstaticjvmtiagent", ], platform_apis: true, - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "mts-crashrecovery", + ], + min_sdk_version: "36", } diff --git a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java index 8ac3433033c6..c2ab0550ea05 100644 --- a/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java +++ b/tests/PackageWatchdog/src/com/android/server/CrashRecoveryTest.java @@ -48,8 +48,6 @@ import android.net.ConnectivityModuleConnector.ConnectivityModuleHealthListener; import android.os.Handler; import android.os.SystemProperties; import android.os.test.TestLooper; -import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.DeviceConfig; import android.util.AtomicFile; @@ -135,7 +133,6 @@ public class CrashRecoveryTest { @Before public void setUp() throws Exception { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); MockitoAnnotations.initMocks(this); new File(InstrumentationRegistry.getContext().getFilesDir(), "package-watchdog.xml").delete(); @@ -305,90 +302,6 @@ public class CrashRecoveryTest { } @Test - @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) - public void testBootLoopWithRescuePartyAndRollbackObserver() throws Exception { - PackageWatchdog watchdog = createWatchdog(); - RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); - RollbackPackageHealthObserver rollbackObserver = - setUpRollbackPackageHealthObserver(watchdog); - - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(1); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(1); - for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { - watchdog.noteBoot(); - } - mTestLooper.dispatchAll(); - verify(rescuePartyObserver).onExecuteBootLoopMitigation(1); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(2); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(1); - - watchdog.noteBoot(); - - mTestLooper.dispatchAll(); - verify(rescuePartyObserver).onExecuteBootLoopMitigation(2); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(3); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(2); - - watchdog.noteBoot(); - - mTestLooper.dispatchAll(); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(3); - verify(rollbackObserver).onExecuteBootLoopMitigation(1); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(2); - // Update the list of available rollbacks after executing bootloop mitigation once - when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_HIGH, - ROLLBACK_INFO_MANUAL)); - - watchdog.noteBoot(); - - mTestLooper.dispatchAll(); - verify(rescuePartyObserver).onExecuteBootLoopMitigation(3); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(4); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(2); - - watchdog.noteBoot(); - - mTestLooper.dispatchAll(); - verify(rescuePartyObserver).onExecuteBootLoopMitigation(4); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(5); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(2); - - watchdog.noteBoot(); - - mTestLooper.dispatchAll(); - verify(rescuePartyObserver).onExecuteBootLoopMitigation(5); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(6); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(2); - - watchdog.noteBoot(); - - mTestLooper.dispatchAll(); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(6); - verify(rollbackObserver).onExecuteBootLoopMitigation(2); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(3); - // Update the list of available rollbacks after executing bootloop mitigation - when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_MANUAL)); - - watchdog.noteBoot(); - - mTestLooper.dispatchAll(); - verify(rescuePartyObserver).onExecuteBootLoopMitigation(6); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(7); - verify(rollbackObserver, never()).onExecuteBootLoopMitigation(3); - - moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1); - Mockito.reset(rescuePartyObserver); - - for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { - watchdog.noteBoot(); - } - mTestLooper.dispatchAll(); - verify(rescuePartyObserver).onExecuteBootLoopMitigation(1); - verify(rescuePartyObserver, never()).onExecuteBootLoopMitigation(2); - } - - @Test - @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testBootLoopWithRescuePartyAndRollbackObserverNoFlags() throws Exception { PackageWatchdog watchdog = createWatchdog(); RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); @@ -443,80 +356,6 @@ public class CrashRecoveryTest { } @Test - @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) - public void testCrashLoopWithRescuePartyAndRollbackObserver() throws Exception { - PackageWatchdog watchdog = createWatchdog(); - RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); - RollbackPackageHealthObserver rollbackObserver = - setUpRollbackPackageHealthObserver(watchdog); - VersionedPackage versionedPackageA = new VersionedPackage(APP_A, VERSION_CODE); - - when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> { - ApplicationInfo info = new ApplicationInfo(); - info.flags |= ApplicationInfo.FLAG_PERSISTENT - | ApplicationInfo.FLAG_SYSTEM; - return info; - }); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: SCOPED_DEVICE_CONFIG_RESET - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: ALL_DEVICE_CONFIG_RESET - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: WARM_REBOOT - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: Low impact rollback - verify(rollbackObserver).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); - - // update available rollbacks to mock rollbacks being applied after the call to - // rollbackObserver.onExecuteHealthCheckMitigation - when(mRollbackManager.getAvailableRollbacks()).thenReturn( - List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL)); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageA), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // DEFAULT_MAJOR_USER_IMPACT_LEVEL_THRESHOLD reached. No more mitigations applied - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageA, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - } - - @Test - @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testCrashLoopWithRescuePartyAndRollbackObserverEnableDeprecateFlagReset() throws Exception { PackageWatchdog watchdog = createWatchdog(); @@ -569,123 +408,6 @@ public class CrashRecoveryTest { } @Test - @DisableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) - public void testCrashLoopSystemUIWithRescuePartyAndRollbackObserver() throws Exception { - PackageWatchdog watchdog = createWatchdog(); - RescuePartyObserver rescuePartyObserver = setUpRescuePartyObserver(watchdog); - RollbackPackageHealthObserver rollbackObserver = - setUpRollbackPackageHealthObserver(watchdog); - String systemUi = "com.android.systemui"; - VersionedPackage versionedPackageUi = new VersionedPackage( - systemUi, VERSION_CODE); - RollbackInfo rollbackInfoUi = getRollbackInfo(systemUi, VERSION_CODE, 1, - PackageManager.ROLLBACK_USER_IMPACT_LOW); - when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(ROLLBACK_INFO_LOW, - ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL, rollbackInfoUi)); - - when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).then(inv -> { - ApplicationInfo info = new ApplicationInfo(); - info.flags |= ApplicationInfo.FLAG_PERSISTENT - | ApplicationInfo.FLAG_SYSTEM; - return info; - }); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: SCOPED_DEVICE_CONFIG_RESET - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: ALL_DEVICE_CONFIG_RESET - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: WARM_REBOOT - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 3); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: Low impact rollback - verify(rollbackObserver).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 1); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - - // update available rollbacks to mock rollbacks being applied after the call to - // rollbackObserver.onExecuteHealthCheckMitigation - when(mRollbackManager.getAvailableRollbacks()).thenReturn( - List.of(ROLLBACK_INFO_HIGH, ROLLBACK_INFO_MANUAL)); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: RESET_SETTINGS_UNTRUSTED_DEFAULTS - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 4); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 5); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: RESET_SETTINGS_UNTRUSTED_CHANGES - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 5); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 6); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: RESET_SETTINGS_TRUSTED_DEFAULTS - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 6); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 7); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(versionedPackageUi), PackageWatchdog.FAILURE_REASON_APP_CRASH); - - // Mitigation: Factory reset. High impact rollbacks are performed only for boot loops. - verify(rescuePartyObserver).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 7); - verify(rescuePartyObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 8); - verify(rollbackObserver, never()).onExecuteHealthCheckMitigation(versionedPackageUi, - PackageWatchdog.FAILURE_REASON_APP_CRASH, 2); - } - - @Test - @EnableFlags(Flags.FLAG_DEPRECATE_FLAGS_AND_SETTINGS_RESETS) public void testCrashLoopSystemUIWithRescuePartyAndRollbackObserverEnableDeprecateFlagReset() throws Exception { PackageWatchdog watchdog = createWatchdog(); @@ -1043,8 +765,6 @@ public class CrashRecoveryTest { watchdog.notifyPackageFailure(packages, failureReason); } mTestLooper.dispatchAll(); - if (Flags.recoverabilityDetection()) { - moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS); - } + moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS); } } diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 1c50cb1b55fd..b8274841f65b 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -150,7 +150,6 @@ public class PackageWatchdogTest { @Before public void setUp() throws Exception { - mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); MockitoAnnotations.initMocks(this); new File(InstrumentationRegistry.getContext().getFilesDir(), "package-watchdog.xml").delete(); @@ -480,60 +479,6 @@ public class PackageWatchdogTest { assertThat(observer.mHealthCheckFailedPackages).isEmpty(); } - - /** - * Test package failure and notifies only least impact observers. - */ - @Test - public void testPackageFailureNotifyAllDifferentImpacts() throws Exception { - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - PackageWatchdog watchdog = createWatchdog(); - TestObserver observerNone = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_0); - TestObserver observerHigh = new TestObserver(OBSERVER_NAME_2, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); - TestObserver observerMid = new TestObserver(OBSERVER_NAME_3, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); - TestObserver observerLow = new TestObserver(OBSERVER_NAME_4, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); - - // Start observing for all impact observers - watchdog.registerHealthObserver(mTestExecutor, observerNone); - watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B, APP_C, APP_D), - SHORT_DURATION, observerNone); - watchdog.registerHealthObserver(mTestExecutor, observerHigh); - watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B, APP_C), SHORT_DURATION, - observerHigh); - watchdog.registerHealthObserver(mTestExecutor, observerMid); - watchdog.startExplicitHealthCheck(Arrays.asList(APP_A, APP_B), SHORT_DURATION, - observerMid); - watchdog.registerHealthObserver(mTestExecutor, observerLow); - watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observerLow); - - // Then fail all apps above the threshold - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), - new VersionedPackage(APP_B, VERSION_CODE), - new VersionedPackage(APP_C, VERSION_CODE), - new VersionedPackage(APP_D, VERSION_CODE)), - PackageWatchdog.FAILURE_REASON_UNKNOWN); - - // Verify least impact observers are notifed of package failures - List<String> observerNonePackages = observerNone.mMitigatedPackages; - List<String> observerHighPackages = observerHigh.mMitigatedPackages; - List<String> observerMidPackages = observerMid.mMitigatedPackages; - List<String> observerLowPackages = observerLow.mMitigatedPackages; - - // APP_D failure observed by only observerNone is not caught cos its impact is none - assertThat(observerNonePackages).isEmpty(); - // APP_C failure is caught by observerHigh cos it's the lowest impact observer - assertThat(observerHighPackages).containsExactly(APP_C); - // APP_B failure is caught by observerMid cos it's the lowest impact observer - assertThat(observerMidPackages).containsExactly(APP_B); - // APP_A failure is caught by observerLow cos it's the lowest impact observer - assertThat(observerLowPackages).containsExactly(APP_A); - } - @Test public void testPackageFailureNotifyAllDifferentImpactsRecoverability() throws Exception { PackageWatchdog watchdog = createWatchdog(); @@ -583,84 +528,6 @@ public class PackageWatchdogTest { assertThat(observerLowPackages).containsExactly(APP_A); } - /** - * Test package failure and least impact observers are notified successively. - * State transistions: - * - * <ul> - * <li>(observer1:low, observer2:mid) -> {observer1} - * <li>(observer1:high, observer2:mid) -> {observer2} - * <li>(observer1:high, observer2:none) -> {observer1} - * <li>(observer1:none, observer2:none) -> {} - * <ul> - */ - @Test - public void testPackageFailureNotifyLeastImpactSuccessively() throws Exception { - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - PackageWatchdog watchdog = createWatchdog(); - TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); - TestObserver observerSecond = new TestObserver(OBSERVER_NAME_2, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); - - // Start observing for observerFirst and observerSecond with failure handling - watchdog.registerHealthObserver(mTestExecutor, observerFirst); - watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), LONG_DURATION, observerFirst); - watchdog.registerHealthObserver(mTestExecutor, observerSecond); - watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), LONG_DURATION, observerSecond); - - // Then fail APP_A above the threshold - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), - PackageWatchdog.FAILURE_REASON_UNKNOWN); - - // Verify only observerFirst is notifed - assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A); - assertThat(observerSecond.mMitigatedPackages).isEmpty(); - - // After observerFirst handles failure, next action it has is high impact - observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_100; - observerFirst.mMitigatedPackages.clear(); - observerSecond.mMitigatedPackages.clear(); - - // Then fail APP_A again above the threshold - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), - PackageWatchdog.FAILURE_REASON_UNKNOWN); - - // Verify only observerSecond is notifed cos it has least impact - assertThat(observerSecond.mMitigatedPackages).containsExactly(APP_A); - assertThat(observerFirst.mMitigatedPackages).isEmpty(); - - // After observerSecond handles failure, it has no further actions - observerSecond.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; - observerFirst.mMitigatedPackages.clear(); - observerSecond.mMitigatedPackages.clear(); - - // Then fail APP_A again above the threshold - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), - PackageWatchdog.FAILURE_REASON_UNKNOWN); - - // Verify only observerFirst is notifed cos it has the only action - assertThat(observerFirst.mMitigatedPackages).containsExactly(APP_A); - assertThat(observerSecond.mMitigatedPackages).isEmpty(); - - // After observerFirst handles failure, it too has no further actions - observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; - observerFirst.mMitigatedPackages.clear(); - observerSecond.mMitigatedPackages.clear(); - - // Then fail APP_A again above the threshold - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), - PackageWatchdog.FAILURE_REASON_UNKNOWN); - - // Verify no observer is notified cos no actions left - assertThat(observerFirst.mMitigatedPackages).isEmpty(); - assertThat(observerSecond.mMitigatedPackages).isEmpty(); - } - @Test public void testPackageFailureNotifyLeastImpactSuccessivelyRecoverability() throws Exception { PackageWatchdog watchdog = createWatchdog(); @@ -727,34 +594,6 @@ public class PackageWatchdogTest { assertThat(observerSecond.mMitigatedPackages).isEmpty(); } - /** - * Test package failure and notifies only one observer even with observer impact tie. - */ - @Test - public void testPackageFailureNotifyOneSameImpact() throws Exception { - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - PackageWatchdog watchdog = createWatchdog(); - TestObserver observer1 = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); - TestObserver observer2 = new TestObserver(OBSERVER_NAME_2, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); - - // Start observing for observer1 and observer2 with failure handling - watchdog.registerHealthObserver(mTestExecutor, observer2); - watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer2); - watchdog.registerHealthObserver(mTestExecutor, observer1); - watchdog.startExplicitHealthCheck(Arrays.asList(APP_A), SHORT_DURATION, observer1); - - // Then fail APP_A above the threshold - raiseFatalFailureAndDispatch(watchdog, - Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), - PackageWatchdog.FAILURE_REASON_UNKNOWN); - - // Verify only one observer is notifed - assertThat(observer1.mMitigatedPackages).containsExactly(APP_A); - assertThat(observer2.mMitigatedPackages).isEmpty(); - } - @Test public void testPackageFailureNotifyOneSameImpactRecoverabilityDetection() throws Exception { PackageWatchdog watchdog = createWatchdog(); @@ -1015,27 +854,6 @@ public class PackageWatchdogTest { @Test @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_CRASHRECOVERY) - public void testNetworkStackFailure() { - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - final PackageWatchdog wd = createWatchdog(); - - // Start observing with failure handling - TestObserver observer = new TestObserver(OBSERVER_NAME_1, - PackageHealthObserverImpact.USER_IMPACT_LEVEL_100); - wd.startExplicitHealthCheck(Collections.singletonList(APP_A), SHORT_DURATION, observer); - - // Notify of NetworkStack failure - mConnectivityModuleCallbackCaptor.getValue().onNetworkStackFailure(APP_A); - - // Run handler so package failures are dispatched to observers - mTestLooper.dispatchAll(); - - // Verify the NetworkStack observer is notified - assertThat(observer.mMitigatedPackages).containsExactly(APP_A); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_REFACTOR_CRASHRECOVERY) public void testNetworkStackFailureRecoverabilityDetection() { final PackageWatchdog wd = createWatchdog(); @@ -1270,21 +1088,6 @@ public class PackageWatchdogTest { assertThat(persistentObserver.mHealthCheckFailedPackages).isEmpty(); } - - /** Ensure that boot loop mitigation is done when the number of boots meets the threshold. */ - @Test - public void testBootLoopDetection_meetsThreshold() { - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - PackageWatchdog watchdog = createWatchdog(); - TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(mTestExecutor, bootObserver); - for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { - watchdog.noteBoot(); - } - mTestLooper.dispatchAll(); - assertThat(bootObserver.mitigatedBootLoop()).isTrue(); - } - @Test public void testBootLoopDetection_meetsThresholdRecoverability() { PackageWatchdog watchdog = createWatchdog(); @@ -1330,27 +1133,6 @@ public class PackageWatchdogTest { assertThat(bootObserver.mitigatedBootLoop()).isFalse(); } - /** - * Ensure that boot loop mitigation is done for the observer with the lowest user impact - */ - @Test - public void testBootLoopMitigationDoneForLowestUserImpact() { - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - PackageWatchdog watchdog = createWatchdog(); - TestObserver bootObserver1 = new TestObserver(OBSERVER_NAME_1); - bootObserver1.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_10); - TestObserver bootObserver2 = new TestObserver(OBSERVER_NAME_2); - bootObserver2.setImpact(PackageHealthObserverImpact.USER_IMPACT_LEVEL_30); - watchdog.registerHealthObserver(mTestExecutor, bootObserver1); - watchdog.registerHealthObserver(mTestExecutor, bootObserver2); - for (int i = 0; i < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; i++) { - watchdog.noteBoot(); - } - mTestLooper.dispatchAll(); - assertThat(bootObserver1.mitigatedBootLoop()).isTrue(); - assertThat(bootObserver2.mitigatedBootLoop()).isFalse(); - } - @Test public void testBootLoopMitigationDoneForLowestUserImpactRecoverability() { PackageWatchdog watchdog = createWatchdog(); @@ -1368,32 +1150,6 @@ public class PackageWatchdogTest { assertThat(bootObserver2.mitigatedBootLoop()).isFalse(); } - /** - * Ensure that the correct mitigation counts are sent to the boot loop observer. - */ - @Test - public void testMultipleBootLoopMitigation() { - mSetFlagsRule.disableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); - PackageWatchdog watchdog = createWatchdog(); - TestObserver bootObserver = new TestObserver(OBSERVER_NAME_1); - watchdog.registerHealthObserver(mTestExecutor, bootObserver); - for (int i = 0; i < 4; i++) { - for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) { - watchdog.noteBoot(); - } - } - - moveTimeForwardAndDispatch(PackageWatchdog.DEFAULT_DEESCALATION_WINDOW_MS + 1); - - for (int i = 0; i < 4; i++) { - for (int j = 0; j < PackageWatchdog.DEFAULT_BOOT_LOOP_TRIGGER_COUNT; j++) { - watchdog.noteBoot(); - } - } - mTestLooper.dispatchAll(); - assertThat(bootObserver.mBootMitigationCounts).isEqualTo(List.of(1, 2, 3, 4, 1, 2, 3, 4)); - } - @Test public void testMultipleBootLoopMitigationRecoverabilityLowImpact() { PackageWatchdog watchdog = createWatchdog(); @@ -1800,9 +1556,7 @@ public class PackageWatchdogTest { watchdog.notifyPackageFailure(packages, failureReason); } mTestLooper.dispatchAll(); - if (Flags.recoverabilityDetection()) { - moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS); - } + moveTimeForwardAndDispatch(watchdog.DEFAULT_MITIGATION_WINDOW_MS); } private PackageWatchdog createWatchdog() { diff --git a/tests/SoundTriggerTestApp/OWNERS b/tests/SoundTriggerTestApp/OWNERS index a0fcfc52704d..1e41886fe716 100644 --- a/tests/SoundTriggerTestApp/OWNERS +++ b/tests/SoundTriggerTestApp/OWNERS @@ -1,2 +1 @@ include /media/java/android/media/soundtrigger/OWNERS -mdooley@google.com diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java index be0c7daebb57..e62a89b17927 100644 --- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java +++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogCommandHandlerTest.java @@ -19,6 +19,7 @@ package com.android.internal.protolog; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.endsWith; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; @@ -157,13 +158,15 @@ public class ProtoLogCommandHandlerTest { cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP" }); - Mockito.verify(mProtoLogConfigurationService).enableProtoLogToLogcat("MY_GROUP"); + Mockito.verify(mProtoLogConfigurationService) + .enableProtoLogToLogcat(Mockito.any(), eq("MY_GROUP")); cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "enable", "MY_GROUP", "MY_OTHER_GROUP" }); Mockito.verify(mProtoLogConfigurationService) - .enableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); + .enableProtoLogToLogcat(Mockito.any(), + eq("MY_GROUP"), eq("MY_OTHER_GROUP")); } @Test @@ -173,13 +176,15 @@ public class ProtoLogCommandHandlerTest { cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP" }); - Mockito.verify(mProtoLogConfigurationService).disableProtoLogToLogcat("MY_GROUP"); + Mockito.verify(mProtoLogConfigurationService) + .disableProtoLogToLogcat(Mockito.any(), eq("MY_GROUP")); cmdHandler.exec(mMockBinder, FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, new String[] { "logcat", "disable", "MY_GROUP", "MY_OTHER_GROUP" }); Mockito.verify(mProtoLogConfigurationService) - .disableProtoLogToLogcat("MY_GROUP", "MY_OTHER_GROUP"); + .disableProtoLogToLogcat(Mockito.any(), + eq("MY_GROUP"), eq("MY_OTHER_GROUP")); } @Test diff --git a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java index 3be725101252..1f3f91ebf557 100644 --- a/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java +++ b/tests/Tracing/src/com/android/internal/protolog/ProtoLogConfigurationServiceTest.java @@ -62,6 +62,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.PrintWriter; import java.util.List; /** @@ -234,7 +235,7 @@ public class ProtoLogConfigurationServiceTest { service.registerClient(mMockClient, args); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); - service.enableProtoLogToLogcat(TEST_GROUP); + service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); Mockito.verify(mMockClient).toggleLogcat(eq(true), @@ -251,7 +252,7 @@ public class ProtoLogConfigurationServiceTest { service.registerClient(mMockClient, args); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); - service.disableProtoLogToLogcat(TEST_GROUP); + service.disableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); Mockito.verify(mMockClient).toggleLogcat(eq(false), @@ -269,7 +270,7 @@ public class ProtoLogConfigurationServiceTest { service.registerClient(mMockClient, args); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); - service.enableProtoLogToLogcat(OTHER_TEST_GROUP); + service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), OTHER_TEST_GROUP); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isFalse(); Mockito.verify(mMockClient, never()).toggleLogcat(anyBoolean(), any()); @@ -280,7 +281,7 @@ public class ProtoLogConfigurationServiceTest { final ProtoLogConfigurationService service = new ProtoLogConfigurationServiceImpl(); Truth.assertThat(service.getGroups()).asList().doesNotContain(TEST_GROUP); - service.enableProtoLogToLogcat(TEST_GROUP); + service.enableProtoLogToLogcat(Mockito.mock(PrintWriter.class), TEST_GROUP); Truth.assertThat(service.isLoggingToLogcat(TEST_GROUP)).isTrue(); final RegisterClientArgs args = new RegisterClientArgs(); diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java index 1273826c8ef8..8cd89ce89e83 100644 --- a/tests/testables/src/android/testing/TestableLooper.java +++ b/tests/testables/src/android/testing/TestableLooper.java @@ -273,7 +273,7 @@ public class TestableLooper { messages.add(message); } - // Repost all Messages back to the queuewith a new time. + // Repost all Messages back to the queue with a new time. while (true) { Message message = messages.poll(); if (message == null) { diff --git a/tests/utils/testutils/java/android/os/test/TestLooper.java b/tests/utils/testutils/java/android/os/test/TestLooper.java index 83d22d923c78..4d379e45a81a 100644 --- a/tests/utils/testutils/java/android/os/test/TestLooper.java +++ b/tests/utils/testutils/java/android/os/test/TestLooper.java @@ -18,18 +18,24 @@ package android.os.test; import static org.junit.Assert.assertTrue; +import android.os.Build; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.os.SystemClock; +import android.os.TestLooperManager; import android.util.Log; +import androidx.test.platform.app.InstrumentationRegistry; + import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayDeque; +import java.util.Queue; import java.util.concurrent.Executor; /** @@ -44,7 +50,9 @@ import java.util.concurrent.Executor; * The Robolectric class also allows advancing time. */ public class TestLooper { - protected final Looper mLooper; + private final Looper mLooper; + private final TestLooperManager mTestLooperManager; + private final Clock mClock; private static final Constructor<Looper> LOOPER_CONSTRUCTOR; private static final Field THREAD_LOCAL_LOOPER_FIELD; @@ -54,24 +62,46 @@ public class TestLooper { private static final Method MESSAGE_MARK_IN_USE_METHOD; private static final String TAG = "TestLooper"; - private final Clock mClock; - private AutoDispatchThread mAutoDispatchThread; + /** + * Baklava introduces new {@link TestLooperManager} APIs that we can use instead of reflection. + */ + private static boolean isAtLeastBaklava() { + Method[] methods = TestLooperManager.class.getMethods(); + for (Method method : methods) { + if (method.getName().equals("peekWhen")) { + return true; + } + } + return false; + // TODO(shayba): delete the above, uncomment the below. + // SDK_INT has not yet ramped to Baklava in all 25Q2 builds. + // return Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA; + } + static { try { LOOPER_CONSTRUCTOR = Looper.class.getDeclaredConstructor(Boolean.TYPE); LOOPER_CONSTRUCTOR.setAccessible(true); THREAD_LOCAL_LOOPER_FIELD = Looper.class.getDeclaredField("sThreadLocal"); THREAD_LOCAL_LOOPER_FIELD.setAccessible(true); - MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages"); - MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true); - MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); - MESSAGE_NEXT_FIELD.setAccessible(true); - MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); - MESSAGE_WHEN_FIELD.setAccessible(true); - MESSAGE_MARK_IN_USE_METHOD = Message.class.getDeclaredMethod("markInUse"); - MESSAGE_MARK_IN_USE_METHOD.setAccessible(true); + + if (isAtLeastBaklava()) { + MESSAGE_QUEUE_MESSAGES_FIELD = null; + MESSAGE_NEXT_FIELD = null; + MESSAGE_WHEN_FIELD = null; + MESSAGE_MARK_IN_USE_METHOD = null; + } else { + MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages"); + MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true); + MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next"); + MESSAGE_NEXT_FIELD.setAccessible(true); + MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when"); + MESSAGE_WHEN_FIELD.setAccessible(true); + MESSAGE_MARK_IN_USE_METHOD = Message.class.getDeclaredMethod("markInUse"); + MESSAGE_MARK_IN_USE_METHOD.setAccessible(true); + } } catch (NoSuchFieldException | NoSuchMethodException e) { throw new RuntimeException("Failed to initialize TestLooper", e); } @@ -106,6 +136,13 @@ public class TestLooper { throw new RuntimeException("Reflection error constructing or accessing looper", e); } + if (isAtLeastBaklava()) { + mTestLooperManager = + InstrumentationRegistry.getInstrumentation().acquireLooperManager(mLooper); + } else { + mTestLooperManager = null; + } + mClock = clock; } @@ -117,19 +154,61 @@ public class TestLooper { return new HandlerExecutor(new Handler(getLooper())); } - private Message getMessageLinkedList() { + private Message getMessageLinkedListLegacy() { try { MessageQueue queue = mLooper.getQueue(); return (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(queue); } catch (IllegalAccessException e) { throw new RuntimeException("Access failed in TestLooper: get - MessageQueue.mMessages", - e); + e); } } public void moveTimeForward(long milliSeconds) { + if (isAtLeastBaklava()) { + moveTimeForwardBaklava(milliSeconds); + } else { + moveTimeForwardLegacy(milliSeconds); + } + } + + private void moveTimeForwardBaklava(long milliSeconds) { + // Drain all Messages from the queue. + Queue<Message> messages = new ArrayDeque<>(); + while (true) { + Message message = mTestLooperManager.poll(); + if (message == null) { + break; + } + messages.add(message); + } + + // Repost all Messages back to the queue with a new time. + while (true) { + Message message = messages.poll(); + if (message == null) { + break; + } + + // Ugly trick to reset the Message's "in use" flag. + // This is needed because the Message cannot be re-enqueued if it's + // marked in use. + message.copyFrom(message); + + // Adjust the Message's delivery time. + long newWhen = message.getWhen() - milliSeconds; + if (newWhen < 0) { + newWhen = 0; + } + + // Send the Message back to its Handler to be re-enqueued. + message.getTarget().sendMessageAtTime(message, newWhen); + } + } + + private void moveTimeForwardLegacy(long milliSeconds) { try { - Message msg = getMessageLinkedList(); + Message msg = getMessageLinkedListLegacy(); while (msg != null) { long updatedWhen = msg.getWhen() - milliSeconds; if (updatedWhen < 0) { @@ -147,12 +226,12 @@ public class TestLooper { return mClock.uptimeMillis(); } - private Message messageQueueNext() { + private Message messageQueueNextLegacy() { try { long now = currentTime(); Message prevMsg = null; - Message msg = getMessageLinkedList(); + Message msg = getMessageLinkedListLegacy(); if (msg != null && msg.getTarget() == null) { // Stalled by a barrier. Find the next asynchronous message in // the queue. @@ -185,18 +264,46 @@ public class TestLooper { /** * @return true if there are pending messages in the message queue */ - public synchronized boolean isIdle() { - Message messageList = getMessageLinkedList(); + public boolean isIdle() { + if (isAtLeastBaklava()) { + return isIdleBaklava(); + } else { + return isIdleLegacy(); + } + } + + private boolean isIdleBaklava() { + Long when = mTestLooperManager.peekWhen(); + return when != null && currentTime() >= when; + } + private synchronized boolean isIdleLegacy() { + Message messageList = getMessageLinkedListLegacy(); return messageList != null && currentTime() >= messageList.getWhen(); } /** * @return the next message in the Looper's message queue or null if there is none */ - public synchronized Message nextMessage() { + public Message nextMessage() { + if (isAtLeastBaklava()) { + return nextMessageBaklava(); + } else { + return nextMessageLegacy(); + } + } + + private Message nextMessageBaklava() { + if (isIdle()) { + return mTestLooperManager.poll(); + } else { + return null; + } + } + + private synchronized Message nextMessageLegacy() { if (isIdle()) { - return messageQueueNext(); + return messageQueueNextLegacy(); } else { return null; } @@ -206,9 +313,26 @@ public class TestLooper { * Dispatch the next message in the queue * Asserts that there is a message in the queue */ - public synchronized void dispatchNext() { + public void dispatchNext() { + if (isAtLeastBaklava()) { + dispatchNextBaklava(); + } else { + dispatchNextLegacy(); + } + } + + private void dispatchNextBaklava() { + assertTrue(isIdle()); + Message msg = mTestLooperManager.poll(); + if (msg == null) { + return; + } + msg.getTarget().dispatchMessage(msg); + } + + private synchronized void dispatchNextLegacy() { assertTrue(isIdle()); - Message msg = messageQueueNext(); + Message msg = messageQueueNextLegacy(); if (msg == null) { return; } diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp index 51a300bff7ea..661ed07a5669 100644 --- a/tests/vcn/Android.bp +++ b/tests/vcn/Android.bp @@ -16,13 +16,19 @@ android_test { name: "FrameworksVcnTests", // For access hidden connectivity methods in tests defaults: ["framework-connectivity-test-defaults"], + + // TODO: b/374174952 Use 36 after Android B finalization + min_sdk_version: "35", + srcs: [ "java/**/*.java", "java/**/*.kt", ], platform_apis: true, - test_suites: ["device-tests"], - certificate: "platform", + test_suites: [ + "general-tests", + "mts-tethering", + ], static_libs: [ "android.net.vcn.flags-aconfig-java-export", "androidx.test.rules", diff --git a/tests/vcn/AndroidManifest.xml b/tests/vcn/AndroidManifest.xml index a8f657c89f76..08effbd1f7cf 100644 --- a/tests/vcn/AndroidManifest.xml +++ b/tests/vcn/AndroidManifest.xml @@ -16,8 +16,9 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.frameworks.tests.vcn"> - <uses-sdk android:minSdkVersion="33" - android:targetSdkVersion="33"/> + <!-- TODO: b/374174952 Use 36 after Android B finalization --> + <uses-sdk android:minSdkVersion="35" android:targetSdkVersion="35" /> + <application> <uses-library android:name="android.test.runner" /> </application> diff --git a/tests/vcn/AndroidTest.xml b/tests/vcn/AndroidTest.xml index dc521fd7bcd9..9c8362f36cb2 100644 --- a/tests/vcn/AndroidTest.xml +++ b/tests/vcn/AndroidTest.xml @@ -14,12 +14,20 @@ limitations under the License. --> <configuration description="Runs VCN Tests."> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="FrameworksVcnTests.apk" /> </target_preparer> <option name="test-suite-tag" value="apct" /> <option name="test-tag" value="FrameworksVcnTests" /> + + <!-- Run tests in MTS only if the Tethering Mainline module is installed. --> + <object type="module_controller" + class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController"> + <option name="mainline-module-package-name" value="com.google.android.tethering" /> + </object> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.frameworks.tests.vcn" /> <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> diff --git a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java index 156961312323..0fa11ae1fe7d 100644 --- a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java +++ b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java @@ -23,11 +23,24 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.fail; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; + import org.junit.Test; +import org.junit.runner.RunWith; import java.util.HashSet; import java.util.Set; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase { private static final Set<String> ALLOWED_PLMN_IDS = new HashSet<>(); private static final Set<Integer> ALLOWED_CARRIER_IDS = new HashSet<>(); diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java index 73a0a6183cb6..fa97de0aff45 100644 --- a/tests/vcn/java/android/net/vcn/VcnConfigTest.java +++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java @@ -29,11 +29,14 @@ import static org.mockito.Mockito.mock; import android.annotation.NonNull; import android.content.Context; +import android.os.Build; import android.os.Parcel; import android.util.ArraySet; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; @@ -42,7 +45,10 @@ import org.junit.runner.RunWith; import java.util.Collections; import java.util.Set; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnConfigTest { private static final String TEST_PACKAGE_NAME = VcnConfigTest.class.getPackage().getName(); diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index 59dc68900100..990cc74caf6c 100644 --- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -34,10 +34,13 @@ import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; import android.net.vcn.persistablebundleutils.IkeSessionParamsUtilsTest; import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,7 +52,10 @@ import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnGatewayConnectionConfigTest { // Public for use in VcnGatewayConnectionTest diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java index 8461de6d877b..1739fbc0fa6d 100644 --- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java +++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java @@ -38,16 +38,28 @@ import android.net.NetworkCapabilities; import android.net.vcn.VcnManager.VcnStatusCallback; import android.net.vcn.VcnManager.VcnStatusCallbackBinder; import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener; +import android.os.Build; import android.os.ParcelUuid; +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; + import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.net.UnknownHostException; import java.util.UUID; import java.util.concurrent.Executor; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class VcnManagerTest { private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final String GATEWAY_CONNECTION_NAME = "gatewayConnectionName"; diff --git a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java index 7bc9970629a6..52952eb3f2cc 100644 --- a/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java +++ b/tests/vcn/java/android/net/vcn/VcnTransportInfoTest.java @@ -30,12 +30,24 @@ import static org.junit.Assert.fail; import android.net.NetworkCapabilities; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; +import android.os.Build; import android.os.Parcel; +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; + import org.junit.Test; +import org.junit.runner.RunWith; import java.util.Arrays; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class VcnTransportInfoTest { private static final int SUB_ID = 1; private static final int NETWORK_ID = 5; diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java index a674425efea3..c82d2003dbf6 100644 --- a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java +++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java @@ -22,9 +22,21 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import android.net.NetworkCapabilities; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; +import org.junit.runner.RunWith; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class VcnUnderlyingNetworkPolicyTest { private static final VcnUnderlyingNetworkPolicy DEFAULT_NETWORK_POLICY = new VcnUnderlyingNetworkPolicy( diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java index 2110d6ee7c86..22361cc71f12 100644 --- a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java +++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkSpecifierTest.java @@ -22,14 +22,20 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import android.net.TelephonyNetworkSpecifier; +import android.os.Build; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnUnderlyingNetworkSpecifierTest { private static final int[] TEST_SUB_IDS = new int[] {1, 2, 3, 5}; diff --git a/tests/vcn/java/android/net/vcn/VcnUtilsTest.java b/tests/vcn/java/android/net/vcn/VcnUtilsTest.java index 3ce6c8f9386d..fb040d8f9b91 100644 --- a/tests/vcn/java/android/net/vcn/VcnUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/VcnUtilsTest.java @@ -30,13 +30,25 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiInfo; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import java.util.Arrays; import java.util.Collections; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class VcnUtilsTest { private static final int SUB_ID = 1; diff --git a/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java index 4063178e005d..2c072e1cbc88 100644 --- a/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java +++ b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java @@ -22,10 +22,23 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.os.Build; + +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; + import org.junit.Test; +import org.junit.runner.RunWith; import java.util.Set; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class VcnWifiUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase { private static final String SSID = "TestWifi"; diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java index bc8e9d3200b6..01e9ac2ac3cf 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java @@ -21,11 +21,14 @@ import static android.telephony.TelephonyManager.APPTYPE_USIM; import static org.junit.Assert.assertEquals; import android.net.eap.EapSessionConfig; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -35,7 +38,10 @@ import java.nio.charset.StandardCharsets; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class EapSessionConfigUtilsTest { private static final byte[] EAP_ID = "test@android.net".getBytes(StandardCharsets.US_ASCII); diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java index 4f3930f9b5af..821e5a6c94cb 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java @@ -25,10 +25,13 @@ import android.net.ipsec.ike.IkeIpv4AddrIdentification; import android.net.ipsec.ike.IkeIpv6AddrIdentification; import android.net.ipsec.ike.IkeKeyIdIdentification; import android.net.ipsec.ike.IkeRfc822AddrIdentification; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,7 +42,10 @@ import java.net.InetAddress; import javax.security.auth.x500.X500Principal; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class IkeIdentificationUtilsTest { private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeIdentification id) { diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java index 9f7d2390938f..7200aee1c012 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeSessionParamsUtilsTest.java @@ -29,14 +29,16 @@ import android.net.InetAddresses; import android.net.eap.EapSessionConfig; import android.net.ipsec.ike.IkeFqdnIdentification; import android.net.ipsec.ike.IkeSessionParams; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.internal.org.bouncycastle.util.io.pem.PemObject; import com.android.internal.org.bouncycastle.util.io.pem.PemReader; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -52,7 +54,10 @@ import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.util.concurrent.TimeUnit; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class IkeSessionParamsUtilsTest { // Public for use in VcnGatewayConnectionConfigTest, EncryptedTunnelParamsUtilsTest diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java index 28cf38a2a583..957e785d70c0 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeTrafficSelectorUtilsTest.java @@ -20,17 +20,23 @@ import static org.junit.Assert.assertEquals; import android.net.InetAddresses; import android.net.ipsec.ike.IkeTrafficSelector; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; import java.net.InetAddress; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class IkeTrafficSelectorUtilsTest { private static final int START_PORT = 16; diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java index 664044a9e7d4..1e8f5ff2dc07 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java @@ -21,15 +21,21 @@ import static org.junit.Assert.assertEquals; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeSaProposal; import android.net.ipsec.ike.SaProposal; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class SaProposalUtilsTest { /** Package private so that IkeSessionParamsUtilsTest can use it */ diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java index f9dc9eb4d5ae..7d17724112ec 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelConnectionParamsUtilsTest.java @@ -20,14 +20,20 @@ import static org.junit.Assert.assertEquals; import android.net.ipsec.ike.IkeSessionParams; import android.net.ipsec.ike.IkeTunnelConnectionParams; +import android.os.Build; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class TunnelConnectionParamsUtilsTest { // Public for use in VcnGatewayConnectionConfigTest diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java index e0b5f0ef0381..3d7348a79b8c 100644 --- a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java @@ -25,10 +25,13 @@ import android.net.InetAddresses; import android.net.ipsec.ike.ChildSaProposal; import android.net.ipsec.ike.IkeTrafficSelector; import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -37,7 +40,10 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.util.concurrent.TimeUnit; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class TunnelModeChildSessionParamsUtilsTest { // Package private for use in EncryptedTunnelParamsUtilsTest diff --git a/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java b/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java index 47638b002f37..99c7aa72146b 100644 --- a/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/util/MtuUtilsTest.java @@ -33,9 +33,12 @@ import static org.junit.Assert.assertTrue; import static java.util.Collections.emptyList; import android.net.ipsec.ike.ChildSaProposal; +import android.os.Build; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -43,7 +46,10 @@ import org.junit.runner.RunWith; import java.util.Arrays; import java.util.List; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class MtuUtilsTest { private void verifyUnderlyingMtuZero(boolean isIpv4) { diff --git a/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java b/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java index c84e60086b37..f7786af840ee 100644 --- a/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java +++ b/tests/vcn/java/android/net/vcn/util/PersistableBundleUtilsTest.java @@ -21,10 +21,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Test; import org.junit.runner.RunWith; @@ -35,7 +38,10 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class PersistableBundleUtilsTest { private static final String TEST_KEY = "testKey"; diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 26a2a0636792..a97f9a837bab 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -79,6 +79,7 @@ import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.vcn.util.PersistableBundleUtils; import android.net.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; +import android.os.Build; import android.os.IBinder; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -93,7 +94,6 @@ import android.telephony.TelephonyManager; import android.util.ArraySet; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.VcnManagementService.VcnStatusCallbackInfo; @@ -101,6 +101,8 @@ import com.android.server.vcn.TelephonySubscriptionTracker; import com.android.server.vcn.Vcn; import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Rule; @@ -117,8 +119,10 @@ import java.util.Map.Entry; import java.util.Set; import java.util.UUID; -/** Tests for {@link VcnManagementService}. */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnManagementServiceTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java index 77f82f0d8cf4..6276be27fbf5 100644 --- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java @@ -54,6 +54,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.vcn.VcnManager; +import android.os.Build; import android.os.Handler; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -69,9 +70,10 @@ import android.util.ArrayMap; import android.util.ArraySet; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.modules.utils.HandlerExecutor; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; @@ -87,8 +89,10 @@ import java.util.Map; import java.util.Set; import java.util.UUID; -/** Tests for TelephonySubscriptionTracker */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class TelephonySubscriptionTrackerTest { private static final String PACKAGE_NAME = diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 74db6a5211a0..6608dda95a4b 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -70,16 +70,18 @@ import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnTransportInfo; import android.net.vcn.util.MtuUtils; +import android.os.Build; import android.os.PersistableBundle; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; @@ -94,8 +96,10 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; -/** Tests for VcnGatewayConnection.ConnectedState */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase { private static final int PARALLEL_SA_COUNT = 4; diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index 3c70759a2fa6..f6123d29f35a 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -26,17 +26,22 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.net.ipsec.ike.IkeSessionParams; +import android.os.Build; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -/** Tests for VcnGatewayConnection.ConnectingState */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectionTestBase { private VcnIkeSession mIkeSession; diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index f3eb82f46de7..7cfaf5be5111 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -30,16 +30,21 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.net.IpSecManager; +import android.os.Build; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -/** Tests for VcnGatewayConnection.DisconnectedState */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase { @Before diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 78aefad9f8ff..9132d830c54e 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -23,15 +23,21 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.os.Build; + import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -/** Tests for VcnGatewayConnection.DisconnectedState */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnectionTestBase { @Before diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 6568cdd44377..d5ef4e028709 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -27,15 +27,21 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.os.Build; + import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -/** Tests for VcnGatewayConnection.RetryTimeoutState */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnectionTestBase { private long mFirstRetryInterval; diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java index b9fe76a24d20..5283322682ee 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -61,15 +61,17 @@ import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnManager; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; +import android.os.Build; import android.os.ParcelUuid; import android.os.Process; import android.telephony.SubscriptionInfo; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; @@ -87,8 +89,10 @@ import java.util.UUID; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -/** Tests for TelephonySubscriptionTracker */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { private static final int TEST_UID = Process.myUid() + 1; diff --git a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java index e9026e22b6b2..2b92428918db 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnNetworkProviderTest.java @@ -29,12 +29,14 @@ import android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkRequest; +import android.os.Build; import android.os.test.TestLooper; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; @@ -44,8 +46,10 @@ import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.List; -/** Tests for TelephonySubscriptionTracker */ -@RunWith(AndroidJUnit4.class) +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) @SmallTest public class VcnNetworkProviderTest { private static final int TEST_SCORE_UNSATISFIED = 0; diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java index 6d269686e42f..bd4aeba761da 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java @@ -49,20 +49,26 @@ import android.net.Uri; import android.net.vcn.VcnConfig; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.os.Build; import android.os.ParcelUuid; import android.os.test.TestLooper; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.ArraySet; +import androidx.test.filters.SmallTest; + import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.Vcn.VcnUserMobileDataStateListener; import com.android.server.vcn.VcnNetworkProvider.NetworkRequestListener; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.util.ArrayList; @@ -73,6 +79,11 @@ import java.util.Map.Entry; import java.util.Set; import java.util.UUID; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class VcnTest { private static final String PKG_NAME = VcnTest.class.getPackage().getName(); private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0)); diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java index c11b6bb3435d..53a36d3e4d6a 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -44,16 +44,22 @@ import static org.mockito.Mockito.when; import android.content.BroadcastReceiver; import android.content.Intent; import android.net.IpSecTransformState; +import android.os.Build; import android.os.OutcomeReceiver; import android.os.PowerManager; +import androidx.test.filters.SmallTest; + import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculationResult; import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator; import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper; import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; @@ -63,6 +69,11 @@ import java.util.Arrays; import java.util.BitSet; import java.util.concurrent.TimeUnit; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { private static final String TAG = IpSecPacketLossDetectorTest.class.getSimpleName(); diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 4f34f9f8f74c..a9c637f7c943 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -42,16 +42,28 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; +import android.os.Build; import android.os.PersistableBundle; import android.util.ArraySet; +import androidx.test.filters.SmallTest; + +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; + import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import java.util.Collections; import java.util.List; import java.util.Set; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class NetworkPriorityClassifierTest extends NetworkEvaluationTestBase { private UnderlyingNetworkRecord mWifiNetworkRecord; private UnderlyingNetworkRecord mCellNetworkRecord; diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index e540932d0e1f..99c508c139ec 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -58,6 +58,7 @@ import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnCellUnderlyingNetworkTemplateTest; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.os.Build; import android.os.ParcelUuid; import android.os.test.TestLooper; import android.telephony.CarrierConfigManager; @@ -65,6 +66,8 @@ import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; import android.util.ArraySet; +import androidx.test.filters.SmallTest; + import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; @@ -73,9 +76,12 @@ import com.android.server.vcn.routeselection.UnderlyingNetworkController.Network import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener; import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; @@ -89,6 +95,11 @@ import java.util.List; import java.util.Set; import java.util.UUID; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class UnderlyingNetworkControllerTest { private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final int INITIAL_SUB_ID_1 = 1; diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java index a315b0690ec5..27c1bc105bde 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java @@ -38,19 +38,30 @@ import static org.mockito.Mockito.when; import android.net.IpSecTransform; import android.net.vcn.VcnGatewayConnectionConfig; +import android.os.Build; + +import androidx.test.filters.SmallTest; import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.Dependencies; import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; +import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRunner; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import java.util.concurrent.TimeUnit; +// TODO: b/374174952 After B finalization, use Sdk36ModuleController to ensure VCN tests only run on +// Android B/B+ +@RunWith(DevSdkIgnoreRunner.class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM) +@SmallTest public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase { private static final int PENALTY_TIMEOUT_MIN = 10; private static final long PENALTY_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(PENALTY_TIMEOUT_MIN); diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index ff4d8ef2ec25..0a5cb1ff4956 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -2649,6 +2649,10 @@ int LinkCommand::Action(const std::vector<std::string>& args) { ".mpg", ".mpeg", ".mp4", ".m4a", ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", ".wma", ".wmv", ".webm", ".mkv"}); + if (options_.no_compress_fonts) { + options_.extensions_to_not_compress.insert({".ttf", ".otf", ".ttc"}); + } + // Turn off auto versioning for static-libs. if (context.GetPackageType() == PackageType::kStaticLib) { options_.no_auto_version = true; diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h index 2f17853718ec..977978834fcd 100644 --- a/tools/aapt2/cmd/Link.h +++ b/tools/aapt2/cmd/Link.h @@ -78,6 +78,7 @@ struct LinkOptions { bool use_sparse_encoding = false; std::unordered_set<std::string> extensions_to_not_compress; std::optional<std::regex> regex_to_not_compress; + bool no_compress_fonts = false; FeatureFlagValues feature_flag_values; // Static lib options. @@ -300,6 +301,14 @@ class LinkCommand : public Command { "use the '$' symbol for end of line. Uses a case-sensitive ECMAScript" "regular expression grammar.", &no_compress_regex); + AddOptionalSwitch("--no-compress-fonts", + "Do not compress files with common extensions for fonts.\n" + "This allows loading fonts directly from the APK, without needing to\n" + "decompress them first. Loading fonts will be faster and use less memory.\n" + "The downside is that the APK will be larger.\n" + "Passing this flag is functionally equivalent to passing the following flags:\n" + "-0 .ttf -0 .otf -0 .ttc", + &options_.no_compress_fonts); AddOptionalSwitch("--warn-manifest-validation", "Treat manifest validation errors as warnings.", &options_.manifest_fixer_options.warn_validation); diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp index a2dc8f8ce0fd..41f8e250efd7 100644 --- a/tools/aapt2/cmd/Link_test.cpp +++ b/tools/aapt2/cmd/Link_test.cpp @@ -98,6 +98,7 @@ TEST_F(LinkTest, NoCompressAssets) { WriteFile(GetTestPath("assets/test.txt"), content); WriteFile(GetTestPath("assets/test.hello.txt"), content); WriteFile(GetTestPath("assets/test.hello.xml"), content); + WriteFile(GetTestPath("assets/fonts/myfont.ttf"), content); const std::string out_apk = GetTestPath("out.apk"); std::vector<std::string> link_args = { @@ -136,6 +137,10 @@ TEST_F(LinkTest, NoCompressAssets) { file = zip->FindFile("assets/test.hello.xml"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_FALSE(file->WasCompressed()); + + file = zip->FindFile("assets/fonts/myfont.ttf"); + ASSERT_THAT(file, Ne(nullptr)); + EXPECT_TRUE(file->WasCompressed()); } TEST_F(LinkTest, NoCompressResources) { @@ -182,6 +187,42 @@ TEST_F(LinkTest, NoCompressResources) { EXPECT_FALSE(file->WasCompressed()); } +TEST_F(LinkTest, NoCompressFonts) { + StdErrDiagnostics diag; + std::string content(500, 'a'); + const std::string compiled_files_dir = GetTestPath("compiled"); + ASSERT_TRUE(CompileFile(GetTestPath("res/raw/test.txt"), content, compiled_files_dir, &diag)); + WriteFile(GetTestPath("assets/fonts/myfont1.ttf"), content); + WriteFile(GetTestPath("assets/fonts/myfont2.ttf"), content); + + const std::string out_apk = GetTestPath("out.apk"); + std::vector<std::string> link_args = { + "--manifest", GetDefaultManifest(), + "-o", out_apk, + "--no-compress-fonts", + "-A", GetTestPath("assets") + }; + + ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag)); + + std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_apk, &diag); + ASSERT_THAT(apk, Ne(nullptr)); + io::IFileCollection* zip = apk->GetFileCollection(); + ASSERT_THAT(zip, Ne(nullptr)); + + auto file = zip->FindFile("res/raw/test.txt"); + ASSERT_THAT(file, Ne(nullptr)); + EXPECT_TRUE(file->WasCompressed()); + + file = zip->FindFile("assets/fonts/myfont1.ttf"); + ASSERT_THAT(file, Ne(nullptr)); + EXPECT_FALSE(file->WasCompressed()); + + file = zip->FindFile("assets/fonts/myfont2.ttf"); + ASSERT_THAT(file, Ne(nullptr)); + EXPECT_FALSE(file->WasCompressed()); +} + TEST_F(LinkTest, OverlayStyles) { StdErrDiagnostics diag; const std::string compiled_files_dir = GetTestPath("compiled"); diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md index 5c3dfdcadfec..6bdbaaed9858 100644 --- a/tools/aapt2/readme.md +++ b/tools/aapt2/readme.md @@ -3,6 +3,8 @@ ## Version 2.20 - Too many features, bug fixes, and improvements to list since the last minor version update in 2017. This README will be updated more frequently in the future. +- Added a new flag `--no-compress-fonts`. This can significantly speed up loading fonts from APK + assets, at the cost of increasing the storage size of the APK. ## Version 2.19 - Added navigation resource type. |