diff options
422 files changed, 19251 insertions, 4067 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index fe80d1be9532..8fad79a845b4 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -5926,9 +5926,6 @@ public class JobSchedulerService extends com.android.server.SystemService pw.print(Flags.FLAG_DO_NOT_FORCE_RUSH_EXECUTION_AT_BOOT, Flags.doNotForceRushExecutionAtBoot()); pw.println(); - pw.print(android.app.job.Flags.FLAG_BACKUP_JOBS_EXEMPTION, - android.app.job.Flags.backupJobsExemption()); - pw.println(); pw.print(android.app.job.Flags.FLAG_IGNORE_IMPORTANT_WHILE_FOREGROUND, android.app.job.Flags.ignoreImportantWhileForeground()); pw.println(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java index f3bc9c747f17..42c8250a6185 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java @@ -433,9 +433,6 @@ public final class JobSchedulerShellCommand extends BasicShellCommandHandler { case com.android.server.job.Flags.FLAG_DO_NOT_FORCE_RUSH_EXECUTION_AT_BOOT: pw.println(com.android.server.job.Flags.doNotForceRushExecutionAtBoot()); break; - case android.app.job.Flags.FLAG_BACKUP_JOBS_EXEMPTION: - pw.println(android.app.job.Flags.backupJobsExemption()); - break; case android.app.job.Flags.FLAG_IGNORE_IMPORTANT_WHILE_FOREGROUND: pw.println(android.app.job.Flags.ignoreImportantWhileForeground()); break; diff --git a/core/api/current.txt b/core/api/current.txt index 60dad2436f7a..bbdcd6de9cb0 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -34765,6 +34765,7 @@ package android.os { method public android.os.MessageQueue getMessageQueue(); method public boolean hasMessages(android.os.Handler, Object, int); method public boolean hasMessages(android.os.Handler, Object, Runnable); + method @FlaggedApi("android.os.message_queue_testability") public boolean isBlockedOnSyncBarrier(); method public android.os.Message next(); method @FlaggedApi("android.os.message_queue_testability") @Nullable public Long peekWhen(); method @FlaggedApi("android.os.message_queue_testability") @Nullable public android.os.Message pop(); @@ -44887,11 +44888,11 @@ package android.telephony { field public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array"; field public static final String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool"; field public static final String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool"; - field public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int"; - field public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int"; - field public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; - field public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int"; - field public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; field public static final String KEY_CELLULAR_SERVICE_CAPABILITIES_INT_ARRAY = "cellular_service_capabilities_int_array"; field public static final String KEY_CELLULAR_USAGE_SETTING_INT = "cellular_usage_setting_int"; field public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool"; @@ -44918,7 +44919,7 @@ package android.telephony { field public static final String KEY_DEFAULT_VM_NUMBER_ROAMING_AND_IMS_UNREGISTERED_STRING = "default_vm_number_roaming_and_ims_unregistered_string"; field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string"; field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array"; - field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; field public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool"; field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL = "disable_dun_apn_while_roaming_with_preset_apn_bool"; field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool"; @@ -45069,10 +45070,10 @@ package android.telephony { field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final String KEY_SATELLITE_SUPPORTED_MSG_APPS_STRING_ARRAY = "satellite_supported_msg_apps_string_array"; field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; - field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool"; field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool"; - field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool"; field public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool"; field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool"; field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool"; @@ -45102,7 +45103,7 @@ package android.telephony { field public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = "support_enhanced_call_blocking_bool"; field public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL = "support_ims_conference_event_package_bool"; field public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool"; - field public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool"; field public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool"; field public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = "support_tdscdma_roaming_networks_string_array"; field public static final String KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL = "switch_data_to_primary_if_primary_is_oos_bool"; @@ -45112,7 +45113,7 @@ package android.telephony { field public static final String KEY_USE_ACS_FOR_RCS_BOOL = "use_acs_for_rcs_bool"; field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool"; field public static final String KEY_USE_IP_FOR_CALLING_INDICATOR_BOOL = "use_ip_for_calling_indicator_bool"; - field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; field @Deprecated public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool"; field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool"; field public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool"; @@ -45548,13 +45549,13 @@ package android.telephony { field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentity> CREATOR; } - public final class CellIdentityCdma extends android.telephony.CellIdentity { - method public int getBasestationId(); - method public int getLatitude(); - method public int getLongitude(); - method public int getNetworkId(); - method public int getSystemId(); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityCdma> CREATOR; + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CellIdentityCdma extends android.telephony.CellIdentity { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getBasestationId(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getLatitude(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getLongitude(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getNetworkId(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getSystemId(); + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityCdma> CREATOR; } public final class CellIdentityGsm extends android.telephony.CellIdentity { @@ -45646,11 +45647,11 @@ package android.telephony { field public static final long UNAVAILABLE_LONG = 9223372036854775807L; // 0x7fffffffffffffffL } - public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable { - method @NonNull public android.telephony.CellIdentityCdma getCellIdentity(); - method @NonNull public android.telephony.CellSignalStrengthCdma getCellSignalStrength(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoCdma> CREATOR; + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.CellIdentityCdma getCellIdentity(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.CellSignalStrengthCdma getCellSignalStrength(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void writeToParcel(android.os.Parcel, int); + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoCdma> CREATOR; } public final class CellInfoGsm extends android.telephony.CellInfo implements android.os.Parcelable { @@ -47229,11 +47230,11 @@ package android.telephony { method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getImei(int); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}) public String getLine1Number(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public String getManualNetworkSelectionPlmn(); - method @Nullable public String getManufacturerCode(); - method @Nullable public String getManufacturerCode(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @Nullable public String getManufacturerCode(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @Nullable public String getManufacturerCode(int); method public static long getMaximumCallComposerPictureSize(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getMeid(int); method public String getMmsUAProfUrl(); method public String getMmsUserAgent(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNai(); @@ -47379,10 +47380,10 @@ package android.telephony { field public static final int CARRIER_RESTRICTION_STATUS_RESTRICTED = 2; // 0x2 field public static final int CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER = 3; // 0x3 field public static final int CARRIER_RESTRICTION_STATUS_UNKNOWN = 0; // 0x0 - field public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; // 0x1 - field public static final int CDMA_ROAMING_MODE_ANY = 2; // 0x2 - field public static final int CDMA_ROAMING_MODE_HOME = 0; // 0x0 - field public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; // 0xffffffff + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ROAMING_MODE_ANY = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ROAMING_MODE_HOME = 0; // 0x0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; // 0xffffffff field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4 field public static final int DATA_ACTIVITY_IN = 1; // 0x1 field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3 @@ -47402,9 +47403,9 @@ package android.telephony { field public static final int DATA_SUSPENDED = 3; // 0x3 field public static final int DATA_UNKNOWN = -1; // 0xffffffff field public static final int DEFAULT_PORT_INDEX = 0; // 0x0 - field public static final int ERI_FLASH = 2; // 0x2 - field public static final int ERI_OFF = 1; // 0x1 - field public static final int ERI_ON = 0; // 0x0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int ERI_FLASH = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int ERI_OFF = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int ERI_ON = 0; // 0x0 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final String EVENT_DISPLAY_EMERGENCY_MESSAGE = "android.telephony.event.DISPLAY_EMERGENCY_MESSAGE"; field public static final String EXTRA_ACTIVE_SIM_SUPPORTED_COUNT = "android.telephony.extra.ACTIVE_SIM_SUPPORTED_COUNT"; field public static final String EXTRA_APN_PROTOCOL = "android.telephony.extra.APN_PROTOCOL"; @@ -47445,11 +47446,11 @@ package android.telephony { field public static final int NETWORK_SELECTION_MODE_AUTO = 1; // 0x1 field public static final int NETWORK_SELECTION_MODE_MANUAL = 2; // 0x2 field public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; // 0x0 - field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_1xRTT = 7; // 0x7 field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L - field public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final long NETWORK_TYPE_BITMASK_CDMA = 8L; // 0x8L field public static final long NETWORK_TYPE_BITMASK_EDGE = 2L; // 0x2L - field public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final long NETWORK_TYPE_BITMASK_EHRPD = 8192L; // 0x2000L field public static final long NETWORK_TYPE_BITMASK_EVDO_0 = 16L; // 0x10L field public static final long NETWORK_TYPE_BITMASK_EVDO_A = 32L; // 0x20L field public static final long NETWORK_TYPE_BITMASK_EVDO_B = 2048L; // 0x800L @@ -47462,16 +47463,17 @@ package android.telephony { field public static final long NETWORK_TYPE_BITMASK_IWLAN = 131072L; // 0x20000L field public static final long NETWORK_TYPE_BITMASK_LTE = 4096L; // 0x1000L field @Deprecated public static final long NETWORK_TYPE_BITMASK_LTE_CA = 262144L; // 0x40000L + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final long NETWORK_TYPE_BITMASK_NB_IOT_NTN = 1048576L; // 0x100000L field public static final long NETWORK_TYPE_BITMASK_NR = 524288L; // 0x80000L field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L - field public static final int NETWORK_TYPE_CDMA = 4; // 0x4 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_CDMA = 4; // 0x4 field public static final int NETWORK_TYPE_EDGE = 2; // 0x2 - field public static final int NETWORK_TYPE_EHRPD = 14; // 0xe - field public static final int NETWORK_TYPE_EVDO_0 = 5; // 0x5 - field public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6 - field public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_EHRPD = 14; // 0xe + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_EVDO_0 = 5; // 0x5 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_EVDO_A = 6; // 0x6 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int NETWORK_TYPE_EVDO_B = 12; // 0xc field public static final int NETWORK_TYPE_GPRS = 1; // 0x1 field public static final int NETWORK_TYPE_GSM = 16; // 0x10 field public static final int NETWORK_TYPE_HSDPA = 8; // 0x8 @@ -47481,11 +47483,12 @@ package android.telephony { field @Deprecated public static final int NETWORK_TYPE_IDEN = 11; // 0xb field public static final int NETWORK_TYPE_IWLAN = 18; // 0x12 field public static final int NETWORK_TYPE_LTE = 13; // 0xd + field @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") public static final int NETWORK_TYPE_NB_IOT_NTN = 21; // 0x15 field public static final int NETWORK_TYPE_NR = 20; // 0x14 field public static final int NETWORK_TYPE_TD_SCDMA = 17; // 0x11 field public static final int NETWORK_TYPE_UMTS = 3; // 0x3 field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0 - field public static final int PHONE_TYPE_CDMA = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int PHONE_TYPE_CDMA = 2; // 0x2 field public static final int PHONE_TYPE_GSM = 1; // 0x1 field public static final int PHONE_TYPE_NONE = 0; // 0x0 field public static final int PHONE_TYPE_SIP = 3; // 0x3 @@ -58363,6 +58366,7 @@ package android.view.textclassifier { method @NonNull @WorkerThread public default android.view.textclassifier.TextSelection suggestSelection(@NonNull android.view.textclassifier.TextSelection.Request); method @NonNull @WorkerThread public default android.view.textclassifier.TextSelection suggestSelection(@NonNull CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.os.LocaleList); field public static final String EXTRA_FROM_TEXT_CLASSIFIER = "android.view.textclassifier.extra.FROM_TEXT_CLASSIFIER"; + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final String EXTRA_TEXT_ORIGIN_PACKAGE = "android.view.textclassifier.extra.TEXT_ORIGIN_PACKAGE"; field public static final String HINT_TEXT_IS_EDITABLE = "android.text_is_editable"; field public static final String HINT_TEXT_IS_NOT_EDITABLE = "android.text_is_not_editable"; field public static final android.view.textclassifier.TextClassifier NO_OP; @@ -58372,6 +58376,7 @@ package android.view.textclassifier { field public static final String TYPE_EMAIL = "email"; field public static final String TYPE_FLIGHT_NUMBER = "flight"; field public static final String TYPE_OTHER = "other"; + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final String TYPE_OTP = "otp"; field public static final String TYPE_PHONE = "phone"; field public static final String TYPE_UNKNOWN = ""; field public static final String TYPE_URL = "url"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 4a4776dc590e..9590e1ab19c9 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -10,6 +10,7 @@ package android { field @FlaggedApi("android.app.contextualsearch.flags.enable_service") public static final String ACCESS_CONTEXTUAL_SEARCH = "android.permission.ACCESS_CONTEXTUAL_SEARCH"; field public static final String ACCESS_CONTEXT_HUB = "android.permission.ACCESS_CONTEXT_HUB"; field public static final String ACCESS_DRM_CERTIFICATES = "android.permission.ACCESS_DRM_CERTIFICATES"; + field @FlaggedApi("android.permission.flags.fine_power_monitor_permission") public static final String ACCESS_FINE_POWER_MONITORS = "android.permission.ACCESS_FINE_POWER_MONITORS"; field @Deprecated public static final String ACCESS_FM_RADIO = "android.permission.ACCESS_FM_RADIO"; field public static final String ACCESS_FPS_COUNTER = "android.permission.ACCESS_FPS_COUNTER"; field @FlaggedApi("android.multiuser.enable_permission_to_access_hidden_profiles") public static final String ACCESS_HIDDEN_PROFILES_FULL = "android.permission.ACCESS_HIDDEN_PROFILES_FULL"; @@ -26,6 +27,7 @@ package android { field public static final String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS"; field @FlaggedApi("android.app.smartspace.flags.access_smartspace") public static final String ACCESS_SMARTSPACE = "android.permission.ACCESS_SMARTSPACE"; field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER"; + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final String ACCESS_TEXT_CLASSIFIER_BY_TYPE = "android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE"; field public static final String ACCESS_TUNED_INFO = "android.permission.ACCESS_TUNED_INFO"; field public static final String ACCESS_TV_DESCRAMBLER = "android.permission.ACCESS_TV_DESCRAMBLER"; field public static final String ACCESS_TV_SHARED_FILTER = "android.permission.ACCESS_TV_SHARED_FILTER"; @@ -12711,14 +12713,14 @@ package android.security.authenticationpolicy { } @FlaggedApi("android.security.secure_lockdown") public final class DisableSecureLockDeviceParams implements android.os.Parcelable { - ctor public DisableSecureLockDeviceParams(@NonNull String); + ctor public DisableSecureLockDeviceParams(@NonNull CharSequence); method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.DisableSecureLockDeviceParams> CREATOR; } @FlaggedApi("android.security.secure_lockdown") public final class EnableSecureLockDeviceParams implements android.os.Parcelable { - ctor public EnableSecureLockDeviceParams(@NonNull String); + ctor public EnableSecureLockDeviceParams(@NonNull CharSequence); method public int describeContents(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.security.authenticationpolicy.EnableSecureLockDeviceParams> CREATOR; @@ -14630,7 +14632,7 @@ package android.telecom { field public static final int CALLTYPE_INCOMING = 1; // 0x1 field public static final int CALLTYPE_OUTGOING = 2; // 0x2 field public static final int CALLTYPE_UNKNOWN = 0; // 0x0 - field public static final int CDMA_PHONE = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_PHONE = 1; // 0x1 field @NonNull public static final android.os.Parcelable.Creator<android.telecom.ParcelableCallAnalytics> CREATOR; field public static final int GSM_PHONE = 2; // 0x2 field public static final int IMS_PHONE = 4; // 0x4 @@ -15011,7 +15013,7 @@ package android.telephony { field public static final String KEY_GBA_UA_SECURITY_ORGANIZATION_INT = "gba_ua_security_organization_int"; field public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT = "gba_ua_security_protocol_int"; field public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT = "gba_ua_tls_cipher_suite_int"; - field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool"; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool"; } public static final class CarrierConfigManager.Wifi { @@ -15098,8 +15100,8 @@ package android.telephony { ctor public CellBroadcastService(); method @NonNull @WorkerThread public abstract CharSequence getCellBroadcastAreaInfo(int); method @CallSuper public android.os.IBinder onBind(@Nullable android.content.Intent); - method public abstract void onCdmaCellBroadcastSms(int, @NonNull byte[], int); - method public abstract void onCdmaScpMessage(int, @NonNull java.util.List<android.telephony.cdma.CdmaSmsCbProgramData>, @NonNull String, @NonNull java.util.function.Consumer<android.os.Bundle>); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void onCdmaCellBroadcastSms(int, @NonNull byte[], int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void onCdmaScpMessage(int, @NonNull java.util.List<android.telephony.cdma.CdmaSmsCbProgramData>, @NonNull String, @NonNull java.util.function.Consumer<android.os.Bundle>); method public abstract void onGsmCellBroadcastSms(int, @NonNull byte[]); field public static final String CELL_BROADCAST_SERVICE_INTERFACE = "android.telephony.CellBroadcastService"; } @@ -15109,9 +15111,9 @@ package android.telephony { method @NonNull public abstract android.telephony.CellIdentity sanitizeLocationInfo(); } - public final class CellIdentityCdma extends android.telephony.CellIdentity { - method @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation(); - method @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo(); + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CellIdentityCdma extends android.telephony.CellIdentity { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.cdma.CdmaCellLocation asCellLocation(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public android.telephony.CellIdentityCdma sanitizeLocationInfo(); } public final class CellIdentityGsm extends android.telephony.CellIdentity { @@ -15527,16 +15529,16 @@ package android.telephony { field public static final int BUSY = 17; // 0x11 field public static final int CALL_BARRED = 240; // 0xf0 field public static final int CALL_REJECTED = 21; // 0x15 - field public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1 - field public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee - field public static final int CDMA_DROP = 1001; // 0x3e9 - field public static final int CDMA_INTERCEPT = 1002; // 0x3ea - field public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8 - field public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0 - field public static final int CDMA_PREEMPTED = 1007; // 0x3ef - field public static final int CDMA_REORDER = 1003; // 0x3eb - field public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed - field public static final int CDMA_SO_REJECT = 1004; // 0x3ec + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ACCESS_BLOCKED = 1009; // 0x3f1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_ACCESS_FAILURE = 1006; // 0x3ee + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_DROP = 1001; // 0x3e9 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_INTERCEPT = 1002; // 0x3ea + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; // 0x3e8 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_NOT_EMERGENCY = 1008; // 0x3f0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_PREEMPTED = 1007; // 0x3ef + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_REORDER = 1003; // 0x3eb + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_RETRY_ORDER = 1005; // 0x3ed + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SO_REJECT = 1004; // 0x3ec field public static final int CHANNEL_NOT_AVAIL = 44; // 0x2c field public static final int CHANNEL_UNACCEPTABLE = 6; // 0x6 field public static final int CONDITIONAL_IE_ERROR = 100; // 0x64 @@ -16070,14 +16072,14 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageName(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getCarrierServicePackageNameForLogicalSlot(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int); - method public String getCdmaPrlVersion(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaEnhancedRoamingIndicatorDisplayNumber(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public String getCdmaPrlVersion(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaRoamingMode(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCdmaSubscriptionMode(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) public java.util.List<android.telephony.CellBroadcastIdRange> getCellBroadcastIdRanges(); method public int getCurrentPhoneType(); method public int getCurrentPhoneType(int); @@ -16167,7 +16169,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int); method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void resetOtaEmergencyNumberDbFilePath(); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig(); method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int sendThermalMitigationRequest(@NonNull android.telephony.ThermalMitigationRequest); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); @@ -16176,8 +16178,8 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaRoamingMode(int); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCdmaSubscriptionMode(int); method @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS) public void setCellBroadcastIdRanges(@NonNull java.util.List<android.telephony.CellBroadcastIdRange>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean); @@ -16241,9 +16243,9 @@ package android.telephony { field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff - field public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1 - field public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0 - field public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_NV = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; // 0x0 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; // 0xffffffff field public static final int CELL_BROADCAST_RESULT_FAIL_ACTIVATION = 3; // 0x3 field public static final int CELL_BROADCAST_RESULT_FAIL_CONFIG = 2; // 0x2 field public static final int CELL_BROADCAST_RESULT_SUCCESS = 0; // 0x0 @@ -16460,21 +16462,21 @@ package android.telephony { package android.telephony.cdma { - public final class CdmaSmsCbProgramData implements android.os.Parcelable { - method public int describeContents(); - method public int getCategory(); - method public int getOperation(); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003 - field public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001 - field public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff - field public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000 - field public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002 - field public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004 - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.cdma.CdmaSmsCbProgramData> CREATOR; - field public static final int OPERATION_ADD_CATEGORY = 1; // 0x1 - field public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2 - field public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0 + @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public final class CdmaSmsCbProgramData implements android.os.Parcelable { + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int describeContents(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getCategory(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public int getOperation(); + method @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public void writeToParcel(android.os.Parcel, int); + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") @NonNull public static final android.os.Parcelable.Creator<android.telephony.cdma.CdmaSmsCbProgramData> CREATOR; + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_ADD_CATEGORY = 1; // 0x1 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0 } } @@ -17802,7 +17804,7 @@ package android.telephony.ims { field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1 field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; // 0x7 field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; // 0x6 - field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4; // 0x4 + field @Deprecated @FlaggedApi("com.android.internal.telephony.flags.deprecate_cdma") public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4; // 0x4 field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 5; // 0x5 field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_INTERNET_PDN = 12; // 0xc field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 9; // 0x9 @@ -19136,6 +19138,20 @@ package android.view.inputmethod { } +package android.view.textclassifier { + + public final class TextClassificationManager { + method @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE) public android.view.textclassifier.TextClassifier getClassifier(int); + } + + public interface TextClassifier { + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final int CLASSIFIER_TYPE_ANDROID_DEFAULT = 2; // 0x2 + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final int CLASSIFIER_TYPE_DEVICE_DEFAULT = 1; // 0x1 + field @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") public static final int CLASSIFIER_TYPE_SELF_PROVIDED = 0; // 0x0 + } + +} + package android.view.translation { public final class TranslationCapability implements android.os.Parcelable { diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index 7c43891f13f2..3b9ef959e797 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -505,6 +505,8 @@ DeprecationMismatch: javax.microedition.khronos.egl.EGL10#eglCreatePixmapSurface FlaggedApiLiteral: android.Manifest.permission#ACCESS_LAST_KNOWN_CELL_ID: @FlaggedApi contains a string literal, but should reference the field generated by aconfig (com.android.server.telecom.flags.Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES). +FlaggedApiLiteral: android.Manifest.permission#ACCESS_TEXT_CLASSIFIER_BY_TYPE: + @FlaggedApi contains a string literal, but should reference the field generated by aconfig (android.permission.flags.Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED). FlaggedApiLiteral: android.Manifest.permission#BACKUP_HEALTH_CONNECT_DATA_AND_SETTINGS: @FlaggedApi contains a string literal, but should reference the field generated by aconfig (android.permission.flags.Flags.FLAG_HEALTH_CONNECT_BACKUP_RESTORE_PERMISSION_ENABLED). FlaggedApiLiteral: android.Manifest.permission#BIND_VERIFICATION_AGENT: diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 38aea64386a0..03ef669c0675 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1279,7 +1279,24 @@ public class Activity extends ContextThemeWrapper * * <p>This method should be utilized when an activity wants to nudge the user to switch * to the web application in cases where the web may provide the user with a better - * experience. Note that this method does not guarantee that the education will be shown.</p> + * experience. Note that this method does not guarantee that the education will be shown. + * + * <p>The number of times that the "Open in browser" education can be triggered by this method + * is limited per application, and, when shown, the education appears above the app's content. + * For these reasons, developers should use this method sparingly when it is least + * disruptive to the user to show the education and when it is optimal to switch the user to a + * browser session. Before requesting to show the education, developers should assert that they + * have set a link that can be used by the "Open in browser" feature through either + * {@link AssistContent#EXTRA_AUTHENTICATING_USER_WEB_URI} or + * {@link AssistContent#setWebUri} so that users are navigated to a relevant page if they choose + * to switch to the browser. If a URI is not set using either method, "Open in browser" will + * utilize a generic link if available which will direct users to the homepage of the site + * associated with the app. The generic link is provided for a limited number of applications by + * the system and cannot be edited by developers. If none of these options contains a valid URI, + * the user will not be provided with the option to switch to the browser and the education will + * not be shown if requested. + * + * @see android.app.assist.AssistContent#EXTRA_SESSION_TRANSFER_WEB_URI */ @FlaggedApi(com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB_EDUCATION) public final void requestOpenInBrowserEducation() { diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 33ba05865042..69d3e8d4c0d2 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1189,6 +1189,18 @@ public class ActivityManager { return procState == PROCESS_STATE_FOREGROUND_SERVICE; } + /** @hide Should this process state be considered jank perceptible? */ + public static final boolean isProcStateJankPerceptible(int procState) { + if (Flags.jankPerceptibleNarrow()) { + return procState == PROCESS_STATE_PERSISTENT_UI + || procState == PROCESS_STATE_TOP + || procState == PROCESS_STATE_IMPORTANT_FOREGROUND + || procState == PROCESS_STATE_TOP_SLEEPING; + } else { + return !isProcStateCached(procState); + } + } + /** @hide requestType for assist context: only basic information. */ public static final int ASSIST_CONTEXT_BASIC = 0; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 269384362940..48b74f2d0776 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3945,12 +3945,7 @@ public final class ActivityThread extends ClientTransactionHandler if (mLastProcessState == processState) { return; } - // Do not issue a transitional GC if we are transitioning between 2 cached states. - // Only update if the state flips between cached and uncached or vice versa - if (ActivityManager.isProcStateCached(mLastProcessState) - != ActivityManager.isProcStateCached(processState)) { - updateVmProcessState(processState); - } + updateVmProcessState(mLastProcessState, processState); mLastProcessState = processState; if (localLOGV) { Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState @@ -3959,18 +3954,21 @@ public final class ActivityThread extends ClientTransactionHandler } } + /** Converts a process state to a VM process state. */ + private static int toVmProcessState(int processState) { + final int state = ActivityManager.isProcStateJankPerceptible(processState) + ? VM_PROCESS_STATE_JANK_PERCEPTIBLE + : VM_PROCESS_STATE_JANK_IMPERCEPTIBLE; + return state; + } + /** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */ - // Currently ART VM only uses state updates for Transitional GC, and thus - // this function initiates a Transitional GC for transitions into Cached apps states. - private void updateVmProcessState(int processState) { - // Only a transition into Cached state should result in a Transitional GC request - // to the ART runtime. Update VM state to JANK_IMPERCEPTIBLE in that case. - // Note that there are 4 possible cached states currently, all of which are - // JANK_IMPERCEPTIBLE from GC point of view. - final int state = ActivityManager.isProcStateCached(processState) - ? VM_PROCESS_STATE_JANK_IMPERCEPTIBLE - : VM_PROCESS_STATE_JANK_PERCEPTIBLE; - VMRuntime.getRuntime().updateProcessState(state); + private void updateVmProcessState(int lastProcessState, int newProcessState) { + final int state = toVmProcessState(newProcessState); + if (lastProcessState == PROCESS_STATE_UNKNOWN + || state != toVmProcessState(lastProcessState)) { + VMRuntime.getRuntime().updateProcessState(state); + } } @Override diff --git a/core/java/android/app/AppOpsManager.aidl b/core/java/android/app/AppOpsManager.aidl index 56ed290baf2e..b4dee2e937cb 100644 --- a/core/java/android/app/AppOpsManager.aidl +++ b/core/java/android/app/AppOpsManager.aidl @@ -19,7 +19,6 @@ package android.app; parcelable AppOpsManager.PackageOps; parcelable AppOpsManager.NoteOpEventProxyInfo; parcelable AppOpsManager.NoteOpEvent; -parcelable AppOpsManager.NotedOp; parcelable AppOpsManager.OpFeatureEntry; parcelable AppOpsManager.OpEntry; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index c789e28cdbab..19138126698c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -262,24 +262,6 @@ public class AppOpsManager { private static final Object sLock = new Object(); - // A map that records noted times for each op. - private final ArrayMap<NotedOp, Integer> mPendingNotedOps = new ArrayMap<>(); - private final HandlerThread mHandlerThread; - private final Handler mHandler; - private static final int NOTE_OP_BATCHING_DELAY_MILLIS = 1000; - - private boolean isNoteOpBatchingSupported() { - // If noteOp is called from system server no IPC is made, hence we don't need batching. - if (Process.myUid() == Process.SYSTEM_UID) { - return false; - } - return Flags.noteOpBatchingEnabled(); - } - - private final Object mBatchedNoteOpLock = new Object(); - @GuardedBy("mBatchedNoteOpLock") - private boolean mIsBatchedNoteOpCallScheduled = false; - /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */ @GuardedBy("sLock") private static @Nullable OnOpNotedCallback sOnOpNotedCallback; @@ -7484,135 +7466,6 @@ public class AppOpsManager { } /** - * A NotedOp is an app op grouped in noteOp API and sent to the system server in a batch - * - * @hide - */ - public static final class NotedOp implements Parcelable { - private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp; - private final @IntRange(from = 0) int mUid; - private final @Nullable String mPackageName; - private final @Nullable String mAttributionTag; - private final int mVirtualDeviceId; - private final @Nullable String mMessage; - private final boolean mShouldCollectAsyncNotedOp; - private final boolean mShouldCollectMessage; - - public NotedOp(int op, int uid, @Nullable String packageName, - @Nullable String attributionTag, int virtualDeviceId, @Nullable String message, - boolean shouldCollectAsyncNotedOp, boolean shouldCollectMessage) { - mOp = op; - mUid = uid; - mPackageName = packageName; - mAttributionTag = attributionTag; - mVirtualDeviceId = virtualDeviceId; - mMessage = message; - mShouldCollectAsyncNotedOp = shouldCollectAsyncNotedOp; - mShouldCollectMessage = shouldCollectMessage; - } - - NotedOp(Parcel source) { - mOp = source.readInt(); - mUid = source.readInt(); - mPackageName = source.readString(); - mAttributionTag = source.readString(); - mVirtualDeviceId = source.readInt(); - mMessage = source.readString(); - mShouldCollectAsyncNotedOp = source.readBoolean(); - mShouldCollectMessage = source.readBoolean(); - } - - public int getOp() { - return mOp; - } - - public int getUid() { - return mUid; - } - - public @Nullable String getPackageName() { - return mPackageName; - } - - public @Nullable String getAttributionTag() { - return mAttributionTag; - } - - public int getVirtualDeviceId() { - return mVirtualDeviceId; - } - - public @Nullable String getMessage() { - return mMessage; - } - - public boolean getShouldCollectAsyncNotedOp() { - return mShouldCollectAsyncNotedOp; - } - - public boolean getShouldCollectMessage() { - return mShouldCollectMessage; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mOp); - dest.writeInt(mUid); - dest.writeString(mPackageName); - dest.writeString(mAttributionTag); - dest.writeInt(mVirtualDeviceId); - dest.writeString(mMessage); - dest.writeBoolean(mShouldCollectAsyncNotedOp); - dest.writeBoolean(mShouldCollectMessage); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - NotedOp that = (NotedOp) o; - return mOp == that.mOp && mUid == that.mUid && Objects.equals(mPackageName, - that.mPackageName) && Objects.equals(mAttributionTag, that.mAttributionTag) - && mVirtualDeviceId == that.mVirtualDeviceId && Objects.equals(mMessage, - that.mMessage) && Objects.equals(mShouldCollectAsyncNotedOp, - that.mShouldCollectAsyncNotedOp) && Objects.equals(mShouldCollectMessage, - that.mShouldCollectMessage); - } - - @Override - public int hashCode() { - return Objects.hash(mOp, mUid, mPackageName, mAttributionTag, mVirtualDeviceId, - mMessage, mShouldCollectAsyncNotedOp, mShouldCollectMessage); - } - - @Override - public String toString() { - return "NotedOp{" + "mOp=" + mOp + ", mUid=" + mUid + ", mPackageName=" + mPackageName - + ", mAttributionTag=" + mAttributionTag + ", mVirtualDeviceId=" - + mVirtualDeviceId + ", mMessage=" + mMessage + ", mShouldCollectAsyncNotedOp=" - + mShouldCollectAsyncNotedOp + ", mShouldCollectMessage=" - + mShouldCollectMessage + "}"; - } - - - public static final @NonNull Creator<NotedOp> CREATOR = - new Creator<>() { - @Override public NotedOp createFromParcel(Parcel source) { - return new NotedOp(source); - } - - @Override public NotedOp[] newArray(int size) { - return new NotedOp[size]; - } - }; - } - - /** * Computes the sum of the counts for the given flags in between the begin and * end UID states. * @@ -8126,9 +7979,6 @@ public class AppOpsManager { AppOpsManager(Context context, IAppOpsService service) { mContext = context; mService = service; - mHandlerThread = new HandlerThread("AppOpsManager"); - mHandlerThread.start(); - mHandler = mHandlerThread.getThreadHandler(); if (mContext != null) { final PackageManager pm = mContext.getPackageManager(); @@ -9465,74 +9315,15 @@ public class AppOpsManager { } } - SyncNotedAppOp syncOp = null; - boolean skipBinderCall = false; - if (isNoteOpBatchingSupported()) { - int mode = sAppOpModeCache.query( - new AppOpModeQuery(op, uid, packageName, virtualDeviceId, attributionTag, - "noteOpNoThrow")); - // For FOREGROUND mode, we still need to make a binder call to the system service - // to translate it to ALLOWED or IGNORED. So no batching is needed. - if (mode != MODE_FOREGROUND) { - synchronized (mBatchedNoteOpLock) { - NotedOp notedOp = new NotedOp(op, uid, packageName, attributionTag, - virtualDeviceId, message, collectionMode == COLLECT_ASYNC, - shouldCollectMessage); - - // Batch same noteOp calls and send them with their counters to the system - // service asynchronously. The time window for batching is specified in - // NOTE_OP_BATCHING_DELAY_MILLIS. Always allow the first noteOp call to go - // through binder API. Accumulate subsequent same noteOp calls during the - // time window in mPendingNotedOps. - if (!mPendingNotedOps.containsKey(notedOp)) { - mPendingNotedOps.put(notedOp, 0); - } else { - skipBinderCall = true; - mPendingNotedOps.merge(notedOp, 1, Integer::sum); - } - - if (!mIsBatchedNoteOpCallScheduled) { - mHandler.postDelayed(() -> { - ArrayMap<NotedOp, Integer> pendingNotedOpsCopy; - synchronized(mBatchedNoteOpLock) { - mIsBatchedNoteOpCallScheduled = false; - pendingNotedOpsCopy = - new ArrayMap<NotedOp, Integer>(mPendingNotedOps); - mPendingNotedOps.clear(); - } - for (int i = pendingNotedOpsCopy.size() - 1; i >= 0; i--) { - if (pendingNotedOpsCopy.valueAt(i) == 0) { - pendingNotedOpsCopy.removeAt(i); - } - } - if (!pendingNotedOpsCopy.isEmpty()) { - try { - mService.noteOperationsInBatch(pendingNotedOpsCopy); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - }, NOTE_OP_BATCHING_DELAY_MILLIS); - - mIsBatchedNoteOpCallScheduled = true; - } - } - - syncOp = new SyncNotedAppOp(mode, op, attributionTag, packageName); - } - } - - if (!skipBinderCall) { - if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { - syncOp = mService.noteOperation(op, uid, packageName, attributionTag, - collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); - } else { - syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag, - virtualDeviceId, collectionMode == COLLECT_ASYNC, message, - shouldCollectMessage); - } + SyncNotedAppOp syncOp; + if (virtualDeviceId == Context.DEVICE_ID_DEFAULT) { + syncOp = mService.noteOperation(op, uid, packageName, attributionTag, + collectionMode == COLLECT_ASYNC, message, shouldCollectMessage); + } else { + syncOp = mService.noteOperationForDevice(op, uid, packageName, attributionTag, + virtualDeviceId, collectionMode == COLLECT_ASYNC, message, + shouldCollectMessage); } - if (syncOp.getOpMode() == MODE_ALLOWED) { if (collectionMode == COLLECT_SELF) { collectNotedOpForSelf(syncOp); diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 8b7ea0f8b46a..b21defbcc0e3 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -29,7 +29,7 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.UndecFunction; @@ -86,9 +86,9 @@ public abstract class AppOpsManagerInternal { */ SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, int notedCount, - @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String, - Boolean, Integer, SyncNotedAppOp> superImpl); + @Nullable String message, boolean shouldCollectMessage, + @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String, + Boolean, SyncNotedAppOp> superImpl); /** * Allows overriding note proxy operation behavior. diff --git a/core/java/android/app/BroadcastStickyCache.java b/core/java/android/app/BroadcastStickyCache.java index fe2e10752355..0b6cf59876d2 100644 --- a/core/java/android/app/BroadcastStickyCache.java +++ b/core/java/android/app/BroadcastStickyCache.java @@ -35,6 +35,7 @@ import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.view.WindowManagerPolicyConstants; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; @@ -71,8 +72,10 @@ public class BroadcastStickyCache { @VisibleForTesting public static final ArrayMap<String, String> sActionApiNameMap = new ArrayMap<>(); + @GuardedBy("BroadcastStickyCache.class") private static final ArrayMap<String, IpcDataCache.Config> sActionConfigMap = new ArrayMap<>(); + @GuardedBy("BroadcastStickyCache.class") private static final ArrayMap<StickyBroadcastFilter, IpcDataCache<Void, Intent>> sFilterCacheMap = new ArrayMap<>(); @@ -154,37 +157,44 @@ public class BroadcastStickyCache { @Nullable String broadcastPermission, @UserIdInt int userId, @RegisterReceiverFlags int flags) { - IpcDataCache<Void, Intent> intentDataCache = findIpcDataCache(filter); - - if (intentDataCache == null) { - final String action = filter.getAction(0); - final StickyBroadcastFilter stickyBroadcastFilter = - new StickyBroadcastFilter(filter, action); - final Config config = getConfig(action); - - intentDataCache = - new IpcDataCache<>(config, - (query) -> ActivityManager.getService().registerReceiverWithFeature( - applicationThread, - mBasePackageName, - attributionTag, - /* receiverId= */ "null", - /* receiver= */ null, - filter, - broadcastPermission, - userId, - flags)); - sFilterCacheMap.put(stickyBroadcastFilter, intentDataCache); + IpcDataCache<Void, Intent> intentDataCache; + + synchronized (BroadcastStickyCache.class) { + intentDataCache = findIpcDataCache(filter); + + if (intentDataCache == null) { + final String action = filter.getAction(0); + final StickyBroadcastFilter stickyBroadcastFilter = + new StickyBroadcastFilter(filter, action); + final Config config = getConfig(action); + + intentDataCache = + new IpcDataCache<>(config, + (query) -> ActivityManager.getService().registerReceiverWithFeature( + applicationThread, + mBasePackageName, + attributionTag, + /* receiverId= */ "null", + /* receiver= */ null, + filter, + broadcastPermission, + userId, + flags)); + sFilterCacheMap.put(stickyBroadcastFilter, intentDataCache); + } } return intentDataCache.query(null); } @VisibleForTesting public static void clearCacheForTest() { - sFilterCacheMap.clear(); + synchronized (BroadcastStickyCache.class) { + sFilterCacheMap.clear(); + } } @Nullable + @GuardedBy("BroadcastStickyCache.class") private static IpcDataCache<Void, Intent> findIpcDataCache( @NonNull IntentFilter filter) { for (int i = sFilterCacheMap.size() - 1; i >= 0; i--) { @@ -198,6 +208,7 @@ public class BroadcastStickyCache { } @NonNull + @GuardedBy("BroadcastStickyCache.class") private static IpcDataCache.Config getConfig(@NonNull String action) { if (!sActionConfigMap.containsKey(action)) { // We only need 1 entry per cache but just to be on the safer side we are choosing 32 diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig index bea30105f41a..720e045dc944 100644 --- a/core/java/android/app/activity_manager.aconfig +++ b/core/java/android/app/activity_manager.aconfig @@ -156,3 +156,10 @@ flag { bug: "362537357" is_exported: true } + +flag { + name: "jank_perceptible_narrow" + namespace: "system_performance" + description: "Narrow the scope of Jank Perceptible" + bug: "304837972" +} diff --git a/core/java/android/app/jank/JankDataProcessor.java b/core/java/android/app/jank/JankDataProcessor.java index 7ceaeb3fb070..c9472598b352 100644 --- a/core/java/android/app/jank/JankDataProcessor.java +++ b/core/java/android/app/jank/JankDataProcessor.java @@ -215,7 +215,8 @@ public class JankDataProcessor { try { mPendingJankStats.values().forEach(stat -> { - FrameworkStatsLog.write(FrameworkStatsLog.JANK_FRAME_COUNT_BY_WIDGET, + FrameworkStatsLog.write( + FrameworkStatsLog.JANK_FRAME_COUNT_BY_WIDGET_REPORTED, /*app uid*/ stat.getUid(), /*activity name*/ stat.getActivityName(), /*widget id*/ stat.getWidgetId(), diff --git a/core/java/android/companion/DeviceId.java b/core/java/android/companion/DeviceId.java index d9514a02c2b4..2f19eb49ad43 100644 --- a/core/java/android/companion/DeviceId.java +++ b/core/java/android/companion/DeviceId.java @@ -22,7 +22,6 @@ import android.annotation.Nullable; import android.net.MacAddress; import android.os.Parcel; import android.os.Parcelable; -import android.provider.OneTimeUseBuilder; import java.util.Locale; import java.util.Objects; @@ -159,7 +158,7 @@ public final class DeviceId implements Parcelable { * the device: a custom ID using {@link #setCustomId(String)}, or a MAC address using * {@link #setMacAddress(MacAddress)}.</p> */ - public static final class Builder extends OneTimeUseBuilder<DeviceId> { + public static final class Builder { private String mCustomId; private MacAddress mMacAddress; @@ -175,7 +174,6 @@ public final class DeviceId implements Parcelable { */ @NonNull public Builder setCustomId(@Nullable String customId) { - checkNotUsed(); if (customId != null && customId.length() > CUSTOM_ID_LENGTH_LIMIT) { throw new IllegalArgumentException("Length of the custom id must be at most " @@ -195,15 +193,12 @@ public final class DeviceId implements Parcelable { */ @NonNull public Builder setMacAddress(@Nullable MacAddress macAddress) { - checkNotUsed(); mMacAddress = macAddress; return this; } @NonNull - @Override public DeviceId build() { - markUsed(); if (mCustomId == null && mMacAddress == null) { throw new IllegalArgumentException("At least one device id property must be" + "non-null to build a DeviceId."); diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java index 1f7d426d9e6f..211aefffa34c 100644 --- a/core/java/android/hardware/display/DisplayTopology.java +++ b/core/java/android/hardware/display/DisplayTopology.java @@ -91,6 +91,15 @@ public final class DisplayTopology implements Parcelable { @VisibleForTesting public DisplayTopology(TreeNode root, int primaryDisplayId) { mRoot = root; + if (mRoot != null) { + // Set mRoot's position and offset to predictable values, just so we don't leak state + // from some previous arrangement the node was used in, or leak arbitrary values passed + // to the TreeNode constructor. The position and offset don't mean anything because + // mRoot doesn't have a parent. + mRoot.mPosition = POSITION_LEFT; + mRoot.mOffset = 0f; + } + mPrimaryDisplayId = primaryDisplayId; } @@ -422,6 +431,14 @@ public final class DisplayTopology implements Parcelable { } } } + + // Sort children lists by display ID. + final Comparator<TreeNode> idComparator = (d1, d2) -> { + return Integer.compare(d1.mDisplayId, d2.mDisplayId); + }; + for (TreeNode display : displays) { + display.mChildren.sort(idComparator); + } } /** diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index eb7b409e77a6..aaa78aa0916a 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -189,4 +189,11 @@ flag { namespace: "wallet_integration" description: "Adds new API in WindowManager class to check if the window can override the power key double tap behavior." bug: "378736024" - }
\ No newline at end of file + } + +flag { + name: "pointer_acceleration" + namespace: "input" + description: "Allows the user to disable pointer acceleration for mouse and touchpads." + bug: "349006858" +}
\ No newline at end of file diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java index 42028f67f400..e5717ac87d88 100644 --- a/core/java/android/hardware/radio/ProgramSelector.java +++ b/core/java/android/hardware/radio/ProgramSelector.java @@ -43,22 +43,20 @@ import java.util.stream.Stream; * <li>DAB channel info</li> * </ui> * - * <p>The primary ID uniquely identifies a station and can be used for equality - * check. The secondary IDs are supplementary and can speed up tuning process, - * but the primary ID is sufficient (ie. after a full band scan). - * - * <p>Two selectors with different secondary IDs, but the same primary ID are - * considered equal. In particular, secondary IDs vector may get updated for + * <p>Except for DAB radio, two selectors with different secondary IDs, but the same primary + * ID are considered equal. In particular, secondary IDs vector may get updated for * an entry on the program list (ie. when a better frequency for a given - * station is found). + * station is found). For DAB radio, two selectors with the same primary ID and the same + * DAB frequency and DAB ensemble secondary IDs (if exist) are considered equal. * * <p>The primaryId of a given programType MUST be of a specific type: * <ui> - * <li>AM, FM: RDS_PI if the station broadcasts RDS, AMFM_FREQUENCY otherwise;</li> - * <li>AM_HD, FM_HD: HD_STATION_ID_EXT;</li> - * <li>DAB: DAB_SIDECC;</li> - * <li>DRMO: DRMO_SERVICE_ID;</li> - * <li>SXM: SXM_SERVICE_ID;</li> + * <li>AM, FM: {@link #IDENTIFIER_TYPE_RDS_PI} if the station broadcasts RDS, + * {@link #IDENTIFIER_TYPE_AMFM_FREQUENCY} otherwise;</li> + * <li>AM_HD, FM_HD: {@link #IDENTIFIER_TYPE_HD_STATION_ID_EXT};</li> + * <li>DAB: {@link #IDENTIFIER_TYPE_DAB_SID_EXT} or + * {@link #IDENTIFIER_TYPE_DAB_DMB_SID_EXT};</li> + * <li>DRMO: {@link #IDENTIFIER_TYPE_DRMO_SERVICE_ID};</li> * <li>VENDOR: VENDOR_PRIMARY.</li> * </ui> * @hide @@ -597,9 +595,9 @@ public final class ProgramSelector implements Parcelable { * negatives. In particular, it may be way off for certain regions. * The main purpose is to avoid passing improper units, ie. MHz instead of kHz. * - * @param isAm true, if AM, false if FM. + * @param isAm {@code true}, if AM, {@code false} if FM. * @param frequencyKhz the frequency in kHz. - * @return true, if the frequency is roughly valid. + * @return {@code true}, if the frequency is roughly valid. */ private static boolean isValidAmFmFrequency(boolean isAm, int frequencyKhz) { if (isAm) { @@ -785,8 +783,8 @@ public final class ProgramSelector implements Parcelable { * ProgramLists for category entries. * * @see ProgramList.Filter#areCategoriesIncluded - * @return False if this identifier's type is not tunable (e.g. DAB ensemble or - * vendor-specified type). True otherwise. + * @return {@link false} if this identifier's type is not tunable (e.g. DAB ensemble or + * vendor-specified type). {@link true} otherwise. */ public boolean isCategoryType() { return (mType >= IDENTIFIER_TYPE_VENDOR_START && mType <= IDENTIFIER_TYPE_VENDOR_END) diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 11b80ceaeace..ce56a4f63a75 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -1353,6 +1353,69 @@ public final class MessageQueue { } } + /** + * @return true if we are blocked on a sync barrier + */ + boolean isBlockedOnSyncBarrier() { + throwIfNotTest(); + if (mUseConcurrent) { + Iterator<MessageNode> queueIter = mPriorityQueue.iterator(); + MessageNode queueNode = iterateNext(queueIter); + + if (queueNode.isBarrier()) { + long now = SystemClock.uptimeMillis(); + + /* Look for a deliverable async node. If one exists we are not blocked. */ + Iterator<MessageNode> asyncQueueIter = mAsyncPriorityQueue.iterator(); + MessageNode asyncNode = iterateNext(asyncQueueIter); + if (asyncNode != null && now >= asyncNode.getWhen()) { + return false; + } + /* + * Look for a deliverable sync node. In this case, if one exists we are blocked + * since the barrier prevents delivery of the Message. + */ + while (queueNode.isBarrier()) { + queueNode = iterateNext(queueIter); + } + if (queueNode != null && now >= queueNode.getWhen()) { + return true; + } + + return false; + } + } else { + Message msg = mMessages; + if (msg != null && msg.target == null) { + Message iter = msg; + /* Look for a deliverable async node */ + do { + iter = iter.next; + } while (iter != null && !iter.isAsynchronous()); + + long now = SystemClock.uptimeMillis(); + if (iter != null && now >= iter.when) { + return false; + } + /* + * Look for a deliverable sync node. In this case, if one exists we are blocked + * since the barrier prevents delivery of the Message. + */ + iter = msg; + do { + iter = iter.next; + } while (iter != null && (iter.target == null || iter.isAsynchronous())); + + if (iter != null && now >= iter.when) { + return true; + } + return false; + } + } + /* No barrier was found. */ + return false; + } + private static final class MatchHandlerWhatAndObject extends MessageCompare { @Override public boolean compareMessage(MessageNode n, Handler h, int what, Object object, Runnable r, diff --git a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java index 47778ed70847..576c4cc5b442 100644 --- a/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java +++ b/core/java/android/os/ConcurrentMessageQueue/MessageQueue.java @@ -1107,6 +1107,38 @@ public final class MessageQueue { return nextMessage(false); } + /** + * @return true if we are blocked on a sync barrier + */ + boolean isBlockedOnSyncBarrier() { + throwIfNotTest(); + Iterator<MessageNode> queueIter = mPriorityQueue.iterator(); + MessageNode queueNode = iterateNext(queueIter); + + if (queueNode.isBarrier()) { + long now = SystemClock.uptimeMillis(); + + /* Look for a deliverable async node. If one exists we are not blocked. */ + Iterator<MessageNode> asyncQueueIter = mAsyncPriorityQueue.iterator(); + MessageNode asyncNode = iterateNext(asyncQueueIter); + if (asyncNode != null && now >= asyncNode.getWhen()) { + return false; + } + /* + * Look for a deliverable sync node. In this case, if one exists we are blocked + * since the barrier prevents delivery of the Message. + */ + while (queueNode.isBarrier()) { + queueNode = iterateNext(queueIter); + } + if (queueNode != null && now >= queueNode.getWhen()) { + return true; + } + + return false; + } + } + private StateNode getStateNode(StackNode node) { if (node.isMessageNode()) { return ((MessageNode) node).mBottomOfStack; diff --git a/core/java/android/os/LegacyMessageQueue/MessageQueue.java b/core/java/android/os/LegacyMessageQueue/MessageQueue.java index f49acd1edf1a..10d090444c59 100644 --- a/core/java/android/os/LegacyMessageQueue/MessageQueue.java +++ b/core/java/android/os/LegacyMessageQueue/MessageQueue.java @@ -812,6 +812,40 @@ public final class MessageQueue { return legacyPeekOrPop(false); } + /** + * @return true if we are blocked on a sync barrier + */ + boolean isBlockedOnSyncBarrier() { + throwIfNotTest(); + Message msg = mMessages; + if (msg != null && msg.target == null) { + Message iter = msg; + /* Look for a deliverable async node */ + do { + iter = iter.next; + } while (iter != null && !iter.isAsynchronous()); + + long now = SystemClock.uptimeMillis(); + if (iter != null && now >= iter.when) { + return false; + } + /* + * Look for a deliverable sync node. In this case, if one exists we are blocked + * since the barrier prevents delivery of the Message. + */ + iter = msg; + do { + iter = iter.next; + } while (iter != null && (iter.target == null || iter.isAsynchronous())); + + if (iter != null && now >= iter.when) { + return true; + } + return false; + } + return false; + } + boolean hasMessages(Handler h, int what, Object object) { if (h == null) { return false; diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index d7e7ff23439e..cf473ec9c3ea 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -50,7 +50,6 @@ import com.android.internal.util.ArrayUtils; import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; -import dalvik.annotation.optimization.NeverInline; import libcore.util.SneakyThrow; @@ -588,17 +587,6 @@ public final class Parcel { return parcel; } - @NeverInline - private void errorUsedWhileRecycling() { - Log.wtf(TAG, "Parcel used while recycled. " - + Log.getStackTraceString(new Throwable()) - + " Original recycle call (if DEBUG_RECYCLE): ", mStack); - } - - private void assertNotRecycled() { - if (mRecycled) errorUsedWhileRecycling(); - } - /** * Put a Parcel object back into the pool. You must not touch * the object after this call. @@ -647,7 +635,6 @@ public final class Parcel { * @hide */ public void setReadWriteHelper(@Nullable ReadWriteHelper helper) { - assertNotRecycled(); mReadWriteHelper = helper != null ? helper : ReadWriteHelper.DEFAULT; } @@ -657,7 +644,6 @@ public final class Parcel { * @hide */ public boolean hasReadWriteHelper() { - assertNotRecycled(); return (mReadWriteHelper != null) && (mReadWriteHelper != ReadWriteHelper.DEFAULT); } @@ -684,7 +670,6 @@ public final class Parcel { * @hide */ public final void markSensitive() { - assertNotRecycled(); nativeMarkSensitive(mNativePtr); } @@ -701,7 +686,6 @@ public final class Parcel { * @hide */ public final boolean isForRpc() { - assertNotRecycled(); return nativeIsForRpc(mNativePtr); } @@ -709,25 +693,21 @@ public final class Parcel { @ParcelFlags @TestApi public int getFlags() { - assertNotRecycled(); return mFlags; } /** @hide */ public void setFlags(@ParcelFlags int flags) { - assertNotRecycled(); mFlags = flags; } /** @hide */ public void addFlags(@ParcelFlags int flags) { - assertNotRecycled(); mFlags |= flags; } /** @hide */ private boolean hasFlags(@ParcelFlags int flags) { - assertNotRecycled(); return (mFlags & flags) == flags; } @@ -740,7 +720,6 @@ public final class Parcel { // We don't really need to protect it; even if 3p / non-system apps, nothing would happen. // This would only work when used on a reply parcel by a binder object that's allowed-blocking. public void setPropagateAllowBlocking() { - assertNotRecycled(); addFlags(FLAG_PROPAGATE_ALLOW_BLOCKING); } @@ -748,7 +727,6 @@ public final class Parcel { * Returns the total amount of data contained in the parcel. */ public int dataSize() { - assertNotRecycled(); return nativeDataSize(mNativePtr); } @@ -757,7 +735,6 @@ public final class Parcel { * parcel. That is, {@link #dataSize}-{@link #dataPosition}. */ public final int dataAvail() { - assertNotRecycled(); return nativeDataAvail(mNativePtr); } @@ -766,7 +743,6 @@ public final class Parcel { * more than {@link #dataSize}. */ public final int dataPosition() { - assertNotRecycled(); return nativeDataPosition(mNativePtr); } @@ -777,7 +753,6 @@ public final class Parcel { * data buffer. */ public final int dataCapacity() { - assertNotRecycled(); return nativeDataCapacity(mNativePtr); } @@ -789,7 +764,6 @@ public final class Parcel { * @param size The new number of bytes in the Parcel. */ public final void setDataSize(int size) { - assertNotRecycled(); nativeSetDataSize(mNativePtr, size); } @@ -799,7 +773,6 @@ public final class Parcel { * {@link #dataSize}. */ public final void setDataPosition(int pos) { - assertNotRecycled(); nativeSetDataPosition(mNativePtr, pos); } @@ -811,13 +784,11 @@ public final class Parcel { * with this method. */ public final void setDataCapacity(int size) { - assertNotRecycled(); nativeSetDataCapacity(mNativePtr, size); } /** @hide */ public final boolean pushAllowFds(boolean allowFds) { - assertNotRecycled(); return nativePushAllowFds(mNativePtr, allowFds); } @@ -838,7 +809,6 @@ public final class Parcel { * in different versions of the platform. */ public final byte[] marshall() { - assertNotRecycled(); return nativeMarshall(mNativePtr); } @@ -846,18 +816,15 @@ public final class Parcel { * Fills the raw bytes of this Parcel with the supplied data. */ public final void unmarshall(@NonNull byte[] data, int offset, int length) { - assertNotRecycled(); nativeUnmarshall(mNativePtr, data, offset, length); } public final void appendFrom(Parcel parcel, int offset, int length) { - assertNotRecycled(); nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length); } /** @hide */ public int compareData(Parcel other) { - assertNotRecycled(); return nativeCompareData(mNativePtr, other.mNativePtr); } @@ -868,7 +835,6 @@ public final class Parcel { /** @hide */ public final void setClassCookie(Class clz, Object cookie) { - assertNotRecycled(); if (mClassCookies == null) { mClassCookies = new ArrayMap<>(); } @@ -878,13 +844,11 @@ public final class Parcel { /** @hide */ @Nullable public final Object getClassCookie(Class clz) { - assertNotRecycled(); return mClassCookies != null ? mClassCookies.get(clz) : null; } /** @hide */ public void removeClassCookie(Class clz, Object expectedCookie) { - assertNotRecycled(); if (mClassCookies != null) { Object removedCookie = mClassCookies.remove(clz); if (removedCookie != expectedCookie) { @@ -902,25 +866,21 @@ public final class Parcel { * @hide */ public boolean hasClassCookie(Class clz) { - assertNotRecycled(); return mClassCookies != null && mClassCookies.containsKey(clz); } /** @hide */ public final void adoptClassCookies(Parcel from) { - assertNotRecycled(); mClassCookies = from.mClassCookies; } /** @hide */ public Map<Class, Object> copyClassCookies() { - assertNotRecycled(); return new ArrayMap<>(mClassCookies); } /** @hide */ public void putClassCookies(Map<Class, Object> cookies) { - assertNotRecycled(); if (cookies == null) { return; } @@ -940,7 +900,6 @@ public final class Parcel { * if the return value changes. */ public boolean hasFileDescriptors() { - assertNotRecycled(); return nativeHasFileDescriptors(mNativePtr); } @@ -962,7 +921,6 @@ public final class Parcel { * @throws IllegalArgumentException if the parameters are out of the permitted ranges. */ public boolean hasFileDescriptors(int offset, int length) { - assertNotRecycled(); return nativeHasFileDescriptorsInRange(mNativePtr, offset, length); } @@ -1060,7 +1018,6 @@ public final class Parcel { * @hide */ public boolean hasBinders() { - assertNotRecycled(); return nativeHasBinders(mNativePtr); } @@ -1084,7 +1041,6 @@ public final class Parcel { * @hide */ public boolean hasBinders(int offset, int length) { - assertNotRecycled(); return nativeHasBindersInRange(mNativePtr, offset, length); } @@ -1095,7 +1051,6 @@ public final class Parcel { * at the beginning of transactions as a header. */ public final void writeInterfaceToken(@NonNull String interfaceName) { - assertNotRecycled(); nativeWriteInterfaceToken(mNativePtr, interfaceName); } @@ -1106,7 +1061,6 @@ public final class Parcel { * should propagate to the caller. */ public final void enforceInterface(@NonNull String interfaceName) { - assertNotRecycled(); nativeEnforceInterface(mNativePtr, interfaceName); } @@ -1117,7 +1071,6 @@ public final class Parcel { * When used over binder, this exception should propagate to the caller. */ public void enforceNoDataAvail() { - assertNotRecycled(); final int n = dataAvail(); if (n > 0) { throw new BadParcelableException("Parcel data not fully consumed, unread size: " + n); @@ -1134,7 +1087,6 @@ public final class Parcel { * @hide */ public boolean replaceCallingWorkSourceUid(int workSourceUid) { - assertNotRecycled(); return nativeReplaceCallingWorkSourceUid(mNativePtr, workSourceUid); } @@ -1151,7 +1103,6 @@ public final class Parcel { * @hide */ public int readCallingWorkSourceUid() { - assertNotRecycled(); return nativeReadCallingWorkSourceUid(mNativePtr); } @@ -1161,7 +1112,6 @@ public final class Parcel { * @param b Bytes to place into the parcel. */ public final void writeByteArray(@Nullable byte[] b) { - assertNotRecycled(); writeByteArray(b, 0, (b != null) ? b.length : 0); } @@ -1173,7 +1123,6 @@ public final class Parcel { * @param len Number of bytes to write. */ public final void writeByteArray(@Nullable byte[] b, int offset, int len) { - assertNotRecycled(); if (b == null) { writeInt(-1); return; @@ -1195,7 +1144,6 @@ public final class Parcel { * @see #readBlob() */ public final void writeBlob(@Nullable byte[] b) { - assertNotRecycled(); writeBlob(b, 0, (b != null) ? b.length : 0); } @@ -1214,7 +1162,6 @@ public final class Parcel { * @see #readBlob() */ public final void writeBlob(@Nullable byte[] b, int offset, int len) { - assertNotRecycled(); if (b == null) { writeInt(-1); return; @@ -1233,7 +1180,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeInt(int val) { - assertNotRecycled(); int err = nativeWriteInt(mNativePtr, val); if (err != OK) { nativeSignalExceptionForError(err); @@ -1245,7 +1191,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeLong(long val) { - assertNotRecycled(); int err = nativeWriteLong(mNativePtr, val); if (err != OK) { nativeSignalExceptionForError(err); @@ -1257,7 +1202,6 @@ public final class Parcel { * dataPosition(), growing dataCapacity() if needed. */ public final void writeFloat(float val) { - assertNotRecycled(); int err = nativeWriteFloat(mNativePtr, val); if (err != OK) { nativeSignalExceptionForError(err); @@ -1269,7 +1213,6 @@ public final class Parcel { * current dataPosition(), growing dataCapacity() if needed. */ public final void writeDouble(double val) { - assertNotRecycled(); int err = nativeWriteDouble(mNativePtr, val); if (err != OK) { nativeSignalExceptionForError(err); @@ -1281,19 +1224,16 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeString(@Nullable String val) { - assertNotRecycled(); writeString16(val); } /** {@hide} */ public final void writeString8(@Nullable String val) { - assertNotRecycled(); mReadWriteHelper.writeString8(this, val); } /** {@hide} */ public final void writeString16(@Nullable String val) { - assertNotRecycled(); mReadWriteHelper.writeString16(this, val); } @@ -1305,19 +1245,16 @@ public final class Parcel { * @hide */ public void writeStringNoHelper(@Nullable String val) { - assertNotRecycled(); writeString16NoHelper(val); } /** {@hide} */ public void writeString8NoHelper(@Nullable String val) { - assertNotRecycled(); nativeWriteString8(mNativePtr, val); } /** {@hide} */ public void writeString16NoHelper(@Nullable String val) { - assertNotRecycled(); nativeWriteString16(mNativePtr, val); } @@ -1329,7 +1266,6 @@ public final class Parcel { * for true or false, respectively, but may change in the future. */ public final void writeBoolean(boolean val) { - assertNotRecycled(); writeInt(val ? 1 : 0); } @@ -1341,7 +1277,6 @@ public final class Parcel { @UnsupportedAppUsage @RavenwoodThrow(blockedBy = android.text.Spanned.class) public final void writeCharSequence(@Nullable CharSequence val) { - assertNotRecycled(); TextUtils.writeToParcel(val, this, 0); } @@ -1350,7 +1285,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeStrongBinder(IBinder val) { - assertNotRecycled(); nativeWriteStrongBinder(mNativePtr, val); } @@ -1359,7 +1293,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeStrongInterface(IInterface val) { - assertNotRecycled(); writeStrongBinder(val == null ? null : val.asBinder()); } @@ -1374,7 +1307,6 @@ public final class Parcel { * if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p> */ public final void writeFileDescriptor(@NonNull FileDescriptor val) { - assertNotRecycled(); nativeWriteFileDescriptor(mNativePtr, val); } @@ -1383,7 +1315,6 @@ public final class Parcel { * This will be the new name for writeFileDescriptor, for consistency. **/ public final void writeRawFileDescriptor(@NonNull FileDescriptor val) { - assertNotRecycled(); nativeWriteFileDescriptor(mNativePtr, val); } @@ -1394,7 +1325,6 @@ public final class Parcel { * @param value The array of objects to be written. */ public final void writeRawFileDescriptorArray(@Nullable FileDescriptor[] value) { - assertNotRecycled(); if (value != null) { int N = value.length; writeInt(N); @@ -1414,7 +1344,6 @@ public final class Parcel { * the future. */ public final void writeByte(byte val) { - assertNotRecycled(); writeInt(val); } @@ -1430,7 +1359,6 @@ public final class Parcel { * allows you to avoid mysterious type errors at the point of marshalling. */ public final void writeMap(@Nullable Map val) { - assertNotRecycled(); writeMapInternal((Map<String, Object>) val); } @@ -1439,7 +1367,6 @@ public final class Parcel { * growing dataCapacity() if needed. The Map keys must be String objects. */ /* package */ void writeMapInternal(@Nullable Map<String,Object> val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1465,7 +1392,6 @@ public final class Parcel { * growing dataCapacity() if needed. The Map keys must be String objects. */ /* package */ void writeArrayMapInternal(@Nullable ArrayMap<String, Object> val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1495,7 +1421,6 @@ public final class Parcel { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void writeArrayMap(@Nullable ArrayMap<String, Object> val) { - assertNotRecycled(); writeArrayMapInternal(val); } @@ -1514,7 +1439,6 @@ public final class Parcel { */ public <T extends Parcelable> void writeTypedArrayMap(@Nullable ArrayMap<String, T> val, int parcelableFlags) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1536,7 +1460,6 @@ public final class Parcel { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void writeArraySet(@Nullable ArraySet<? extends Object> val) { - assertNotRecycled(); final int size = (val != null) ? val.size() : -1; writeInt(size); for (int i = 0; i < size; i++) { @@ -1549,7 +1472,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeBundle(@Nullable Bundle val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1563,7 +1485,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writePersistableBundle(@Nullable PersistableBundle val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1577,7 +1498,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeSize(@NonNull Size val) { - assertNotRecycled(); writeInt(val.getWidth()); writeInt(val.getHeight()); } @@ -1587,7 +1507,6 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeSizeF(@NonNull SizeF val) { - assertNotRecycled(); writeFloat(val.getWidth()); writeFloat(val.getHeight()); } @@ -1598,7 +1517,6 @@ public final class Parcel { * {@link #writeValue} and must follow the specification there. */ public final void writeList(@Nullable List val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1618,7 +1536,6 @@ public final class Parcel { * {@link #writeValue} and must follow the specification there. */ public final void writeArray(@Nullable Object[] val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1639,7 +1556,6 @@ public final class Parcel { * specification there. */ public final <T> void writeSparseArray(@Nullable SparseArray<T> val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1655,7 +1571,6 @@ public final class Parcel { } public final void writeSparseBooleanArray(@Nullable SparseBooleanArray val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1674,7 +1589,6 @@ public final class Parcel { * @hide */ public final void writeSparseIntArray(@Nullable SparseIntArray val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -1690,7 +1604,6 @@ public final class Parcel { } public final void writeBooleanArray(@Nullable boolean[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1725,7 +1638,6 @@ public final class Parcel { } private void ensureWithinMemoryLimit(int typeSize, @NonNull int... dimensions) { - assertNotRecycled(); // For Multidimensional arrays, Calculate total object // which will be allocated. int totalObjects = 1; @@ -1743,7 +1655,6 @@ public final class Parcel { } private void ensureWithinMemoryLimit(int typeSize, int length) { - assertNotRecycled(); int estimatedAllocationSize = 0; try { estimatedAllocationSize = Math.multiplyExact(typeSize, length); @@ -1767,7 +1678,6 @@ public final class Parcel { @Nullable public final boolean[] createBooleanArray() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_BOOLEAN, N); // >>2 as a fast divide-by-4 works in the create*Array() functions @@ -1785,7 +1695,6 @@ public final class Parcel { } public final void readBooleanArray(@NonNull boolean[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -1798,7 +1707,6 @@ public final class Parcel { /** @hide */ public void writeShortArray(@Nullable short[] val) { - assertNotRecycled(); if (val != null) { int n = val.length; writeInt(n); @@ -1813,7 +1721,6 @@ public final class Parcel { /** @hide */ @Nullable public short[] createShortArray() { - assertNotRecycled(); int n = readInt(); ensureWithinMemoryLimit(SIZE_SHORT, n); if (n >= 0 && n <= (dataAvail() >> 2)) { @@ -1829,7 +1736,6 @@ public final class Parcel { /** @hide */ public void readShortArray(@NonNull short[] val) { - assertNotRecycled(); int n = readInt(); if (n == val.length) { for (int i = 0; i < n; i++) { @@ -1841,7 +1747,6 @@ public final class Parcel { } public final void writeCharArray(@Nullable char[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1855,7 +1760,6 @@ public final class Parcel { @Nullable public final char[] createCharArray() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_CHAR, N); if (N >= 0 && N <= (dataAvail() >> 2)) { @@ -1870,7 +1774,6 @@ public final class Parcel { } public final void readCharArray(@NonNull char[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -1882,7 +1785,6 @@ public final class Parcel { } public final void writeIntArray(@Nullable int[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1896,7 +1798,6 @@ public final class Parcel { @Nullable public final int[] createIntArray() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_INT, N); if (N >= 0 && N <= (dataAvail() >> 2)) { @@ -1911,7 +1812,6 @@ public final class Parcel { } public final void readIntArray(@NonNull int[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -1923,7 +1823,6 @@ public final class Parcel { } public final void writeLongArray(@Nullable long[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1937,7 +1836,6 @@ public final class Parcel { @Nullable public final long[] createLongArray() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_LONG, N); // >>3 because stored longs are 64 bits @@ -1953,7 +1851,6 @@ public final class Parcel { } public final void readLongArray(@NonNull long[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -1965,7 +1862,6 @@ public final class Parcel { } public final void writeFloatArray(@Nullable float[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -1979,7 +1875,6 @@ public final class Parcel { @Nullable public final float[] createFloatArray() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_FLOAT, N); // >>2 because stored floats are 4 bytes @@ -1995,7 +1890,6 @@ public final class Parcel { } public final void readFloatArray(@NonNull float[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -2007,7 +1901,6 @@ public final class Parcel { } public final void writeDoubleArray(@Nullable double[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -2021,7 +1914,6 @@ public final class Parcel { @Nullable public final double[] createDoubleArray() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_DOUBLE, N); // >>3 because stored doubles are 8 bytes @@ -2037,7 +1929,6 @@ public final class Parcel { } public final void readDoubleArray(@NonNull double[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -2049,24 +1940,20 @@ public final class Parcel { } public final void writeStringArray(@Nullable String[] val) { - assertNotRecycled(); writeString16Array(val); } @Nullable public final String[] createStringArray() { - assertNotRecycled(); return createString16Array(); } public final void readStringArray(@NonNull String[] val) { - assertNotRecycled(); readString16Array(val); } /** {@hide} */ public final void writeString8Array(@Nullable String[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -2081,7 +1968,6 @@ public final class Parcel { /** {@hide} */ @Nullable public final String[] createString8Array() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { @@ -2097,7 +1983,6 @@ public final class Parcel { /** {@hide} */ public final void readString8Array(@NonNull String[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -2110,7 +1995,6 @@ public final class Parcel { /** {@hide} */ public final void writeString16Array(@Nullable String[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -2125,7 +2009,6 @@ public final class Parcel { /** {@hide} */ @Nullable public final String[] createString16Array() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { @@ -2141,7 +2024,6 @@ public final class Parcel { /** {@hide} */ public final void readString16Array(@NonNull String[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -2153,7 +2035,6 @@ public final class Parcel { } public final void writeBinderArray(@Nullable IBinder[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -2178,7 +2059,6 @@ public final class Parcel { */ public final <T extends IInterface> void writeInterfaceArray( @SuppressLint("ArrayReturn") @Nullable T[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -2194,7 +2074,6 @@ public final class Parcel { * @hide */ public final void writeCharSequenceArray(@Nullable CharSequence[] val) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -2210,7 +2089,6 @@ public final class Parcel { * @hide */ public final void writeCharSequenceList(@Nullable ArrayList<CharSequence> val) { - assertNotRecycled(); if (val != null) { int N = val.size(); writeInt(N); @@ -2224,7 +2102,6 @@ public final class Parcel { @Nullable public final IBinder[] createBinderArray() { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { @@ -2239,7 +2116,6 @@ public final class Parcel { } public final void readBinderArray(@NonNull IBinder[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -2261,7 +2137,6 @@ public final class Parcel { @Nullable public final <T extends IInterface> T[] createInterfaceArray( @NonNull IntFunction<T[]> newArray, @NonNull Function<IBinder, T> asInterface) { - assertNotRecycled(); int N = readInt(); ensureWithinMemoryLimit(SIZE_COMPLEX_TYPE, N); if (N >= 0) { @@ -2286,7 +2161,6 @@ public final class Parcel { public final <T extends IInterface> void readInterfaceArray( @SuppressLint("ArrayReturn") @NonNull T[] val, @NonNull Function<IBinder, T> asInterface) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -2312,7 +2186,6 @@ public final class Parcel { * @see Parcelable */ public final <T extends Parcelable> void writeTypedList(@Nullable List<T> val) { - assertNotRecycled(); writeTypedList(val, 0); } @@ -2332,7 +2205,6 @@ public final class Parcel { */ public final <T extends Parcelable> void writeTypedSparseArray(@Nullable SparseArray<T> val, int parcelableFlags) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2362,7 +2234,6 @@ public final class Parcel { * @see Parcelable */ public <T extends Parcelable> void writeTypedList(@Nullable List<T> val, int parcelableFlags) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2388,7 +2259,6 @@ public final class Parcel { * @see #readStringList */ public final void writeStringList(@Nullable List<String> val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2414,7 +2284,6 @@ public final class Parcel { * @see #readBinderList */ public final void writeBinderList(@Nullable List<IBinder> val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2437,7 +2306,6 @@ public final class Parcel { * @see #readInterfaceList */ public final <T extends IInterface> void writeInterfaceList(@Nullable List<T> val) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2459,7 +2327,6 @@ public final class Parcel { * @see #readParcelableList(List, ClassLoader) */ public final <T extends Parcelable> void writeParcelableList(@Nullable List<T> val, int flags) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2494,7 +2361,6 @@ public final class Parcel { */ public final <T extends Parcelable> void writeTypedArray(@Nullable T[] val, int parcelableFlags) { - assertNotRecycled(); if (val != null) { int N = val.length; writeInt(N); @@ -2517,7 +2383,6 @@ public final class Parcel { */ public final <T extends Parcelable> void writeTypedObject(@Nullable T val, int parcelableFlags) { - assertNotRecycled(); if (val != null) { writeInt(1); val.writeToParcel(this, parcelableFlags); @@ -2555,7 +2420,6 @@ public final class Parcel { */ public <T> void writeFixedArray(@Nullable T val, int parcelableFlags, @NonNull int... dimensions) { - assertNotRecycled(); if (val == null) { writeInt(-1); return; @@ -2667,7 +2531,6 @@ public final class Parcel { * should be used).</p> */ public final void writeValue(@Nullable Object v) { - assertNotRecycled(); if (v instanceof LazyValue) { LazyValue value = (LazyValue) v; value.writeToParcel(this); @@ -2785,7 +2648,6 @@ public final class Parcel { * @hide */ public void writeValue(int type, @Nullable Object v) { - assertNotRecycled(); switch (type) { case VAL_NULL: break; @@ -2899,7 +2761,6 @@ public final class Parcel { * {@link Parcelable#writeToParcel(Parcel, int) Parcelable.writeToParcel()}. */ public final void writeParcelable(@Nullable Parcelable p, int parcelableFlags) { - assertNotRecycled(); if (p == null) { writeString(null); return; @@ -2915,7 +2776,6 @@ public final class Parcel { * @see #readParcelableCreator */ public final void writeParcelableCreator(@NonNull Parcelable p) { - assertNotRecycled(); String name = p.getClass().getName(); writeString(name); } @@ -2954,7 +2814,6 @@ public final class Parcel { */ @TestApi public boolean allowSquashing() { - assertNotRecycled(); boolean previous = mAllowSquashing; mAllowSquashing = true; return previous; @@ -2966,7 +2825,6 @@ public final class Parcel { */ @TestApi public void restoreAllowSquashing(boolean previous) { - assertNotRecycled(); mAllowSquashing = previous; if (!mAllowSquashing) { mWrittenSquashableParcelables = null; @@ -3023,7 +2881,6 @@ public final class Parcel { * @hide */ public boolean maybeWriteSquashed(@NonNull Parcelable p) { - assertNotRecycled(); if (!mAllowSquashing) { // Don't squash, and don't put it in the map either. writeInt(0); @@ -3074,7 +2931,6 @@ public final class Parcel { @SuppressWarnings("unchecked") @Nullable public <T extends Parcelable> T readSquashed(SquashReadHelper<T> reader) { - assertNotRecycled(); final int offset = readInt(); final int pos = dataPosition(); @@ -3108,7 +2964,6 @@ public final class Parcel { * using the other approaches to writing data in to a Parcel. */ public final void writeSerializable(@Nullable Serializable s) { - assertNotRecycled(); if (s == null) { writeString(null); return; @@ -3161,7 +3016,6 @@ public final class Parcel { */ @RavenwoodReplace(blockedBy = AppOpsManager.class) public final void writeException(@NonNull Exception e) { - assertNotRecycled(); AppOpsManager.prefixParcelWithAppOpsIfNeeded(this); int code = getExceptionCode(e); @@ -3242,7 +3096,6 @@ public final class Parcel { /** @hide */ public void writeStackTrace(@NonNull Throwable e) { - assertNotRecycled(); final int sizePosition = dataPosition(); writeInt(0); // Header size will be filled in later StackTraceElement[] stackTrace = e.getStackTrace(); @@ -3268,7 +3121,6 @@ public final class Parcel { */ @RavenwoodReplace(blockedBy = AppOpsManager.class) public final void writeNoException() { - assertNotRecycled(); AppOpsManager.prefixParcelWithAppOpsIfNeeded(this); // Despite the name of this function ("write no exception"), @@ -3312,7 +3164,6 @@ public final class Parcel { * @see #writeNoException */ public final void readException() { - assertNotRecycled(); int code = readExceptionCode(); if (code != 0) { String msg = readString(); @@ -3336,7 +3187,6 @@ public final class Parcel { @UnsupportedAppUsage @TestApi public final int readExceptionCode() { - assertNotRecycled(); int code = readInt(); if (code == EX_HAS_NOTED_APPOPS_REPLY_HEADER) { AppOpsManager.readAndLogNotedAppops(this); @@ -3370,7 +3220,6 @@ public final class Parcel { * @param msg The exception message. */ public final void readException(int code, String msg) { - assertNotRecycled(); String remoteStackTrace = null; final int remoteStackPayloadSize = readInt(); if (remoteStackPayloadSize > 0) { @@ -3401,7 +3250,6 @@ public final class Parcel { /** @hide */ public Exception createExceptionOrNull(int code, String msg) { - assertNotRecycled(); switch (code) { case EX_PARCELABLE: if (readInt() > 0) { @@ -3434,7 +3282,6 @@ public final class Parcel { * Read an integer value from the parcel at the current dataPosition(). */ public final int readInt() { - assertNotRecycled(); return nativeReadInt(mNativePtr); } @@ -3442,7 +3289,6 @@ public final class Parcel { * Read a long integer value from the parcel at the current dataPosition(). */ public final long readLong() { - assertNotRecycled(); return nativeReadLong(mNativePtr); } @@ -3451,7 +3297,6 @@ public final class Parcel { * dataPosition(). */ public final float readFloat() { - assertNotRecycled(); return nativeReadFloat(mNativePtr); } @@ -3460,7 +3305,6 @@ public final class Parcel { * current dataPosition(). */ public final double readDouble() { - assertNotRecycled(); return nativeReadDouble(mNativePtr); } @@ -3469,19 +3313,16 @@ public final class Parcel { */ @Nullable public final String readString() { - assertNotRecycled(); return readString16(); } /** {@hide} */ public final @Nullable String readString8() { - assertNotRecycled(); return mReadWriteHelper.readString8(this); } /** {@hide} */ public final @Nullable String readString16() { - assertNotRecycled(); return mReadWriteHelper.readString16(this); } @@ -3493,19 +3334,16 @@ public final class Parcel { * @hide */ public @Nullable String readStringNoHelper() { - assertNotRecycled(); return readString16NoHelper(); } /** {@hide} */ public @Nullable String readString8NoHelper() { - assertNotRecycled(); return nativeReadString8(mNativePtr); } /** {@hide} */ public @Nullable String readString16NoHelper() { - assertNotRecycled(); return nativeReadString16(mNativePtr); } @@ -3513,7 +3351,6 @@ public final class Parcel { * Read a boolean value from the parcel at the current dataPosition(). */ public final boolean readBoolean() { - assertNotRecycled(); return readInt() != 0; } @@ -3524,7 +3361,6 @@ public final class Parcel { @UnsupportedAppUsage @Nullable public final CharSequence readCharSequence() { - assertNotRecycled(); return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this); } @@ -3532,7 +3368,6 @@ public final class Parcel { * Read an object from the parcel at the current dataPosition(). */ public final IBinder readStrongBinder() { - assertNotRecycled(); final IBinder result = nativeReadStrongBinder(mNativePtr); // If it's a reply from a method with @PropagateAllowBlocking, then inherit allow-blocking @@ -3548,7 +3383,6 @@ public final class Parcel { * Read a FileDescriptor from the parcel at the current dataPosition(). */ public final ParcelFileDescriptor readFileDescriptor() { - assertNotRecycled(); FileDescriptor fd = nativeReadFileDescriptor(mNativePtr); return fd != null ? new ParcelFileDescriptor(fd) : null; } @@ -3556,7 +3390,6 @@ public final class Parcel { /** {@hide} */ @UnsupportedAppUsage public final FileDescriptor readRawFileDescriptor() { - assertNotRecycled(); return nativeReadFileDescriptor(mNativePtr); } @@ -3567,7 +3400,6 @@ public final class Parcel { **/ @Nullable public final FileDescriptor[] createRawFileDescriptorArray() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -3587,7 +3419,6 @@ public final class Parcel { * @return the FileDescriptor array, or null if the array is null. **/ public final void readRawFileDescriptorArray(FileDescriptor[] val) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -3602,7 +3433,6 @@ public final class Parcel { * Read a byte value from the parcel at the current dataPosition(). */ public final byte readByte() { - assertNotRecycled(); return (byte)(readInt() & 0xff); } @@ -3617,7 +3447,6 @@ public final class Parcel { */ @Deprecated public final void readMap(@NonNull Map outVal, @Nullable ClassLoader loader) { - assertNotRecycled(); readMapInternal(outVal, loader, /* clazzKey */ null, /* clazzValue */ null); } @@ -3631,7 +3460,6 @@ public final class Parcel { public <K, V> void readMap(@NonNull Map<? super K, ? super V> outVal, @Nullable ClassLoader loader, @NonNull Class<K> clazzKey, @NonNull Class<V> clazzValue) { - assertNotRecycled(); Objects.requireNonNull(clazzKey); Objects.requireNonNull(clazzValue); readMapInternal(outVal, loader, clazzKey, clazzValue); @@ -3650,7 +3478,6 @@ public final class Parcel { */ @Deprecated public final void readList(@NonNull List outVal, @Nullable ClassLoader loader) { - assertNotRecycled(); int N = readInt(); readListInternal(outVal, N, loader, /* clazz */ null); } @@ -3672,7 +3499,6 @@ public final class Parcel { */ public <T> void readList(@NonNull List<? super T> outVal, @Nullable ClassLoader loader, @NonNull Class<T> clazz) { - assertNotRecycled(); Objects.requireNonNull(clazz); int n = readInt(); readListInternal(outVal, n, loader, clazz); @@ -3692,7 +3518,6 @@ public final class Parcel { @Deprecated @Nullable public HashMap readHashMap(@Nullable ClassLoader loader) { - assertNotRecycled(); return readHashMapInternal(loader, /* clazzKey */ null, /* clazzValue */ null); } @@ -3707,7 +3532,6 @@ public final class Parcel { @Nullable public <K, V> HashMap<K, V> readHashMap(@Nullable ClassLoader loader, @NonNull Class<? extends K> clazzKey, @NonNull Class<? extends V> clazzValue) { - assertNotRecycled(); Objects.requireNonNull(clazzKey); Objects.requireNonNull(clazzValue); return readHashMapInternal(loader, clazzKey, clazzValue); @@ -3720,7 +3544,6 @@ public final class Parcel { */ @Nullable public final Bundle readBundle() { - assertNotRecycled(); return readBundle(null); } @@ -3732,7 +3555,6 @@ public final class Parcel { */ @Nullable public final Bundle readBundle(@Nullable ClassLoader loader) { - assertNotRecycled(); int length = readInt(); if (length < 0) { if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length); @@ -3753,7 +3575,6 @@ public final class Parcel { */ @Nullable public final PersistableBundle readPersistableBundle() { - assertNotRecycled(); return readPersistableBundle(null); } @@ -3765,7 +3586,6 @@ public final class Parcel { */ @Nullable public final PersistableBundle readPersistableBundle(@Nullable ClassLoader loader) { - assertNotRecycled(); int length = readInt(); if (length < 0) { if (Bundle.DEBUG) Log.d(TAG, "null bundle: length=" + length); @@ -3784,7 +3604,6 @@ public final class Parcel { */ @NonNull public final Size readSize() { - assertNotRecycled(); final int width = readInt(); final int height = readInt(); return new Size(width, height); @@ -3795,7 +3614,6 @@ public final class Parcel { */ @NonNull public final SizeF readSizeF() { - assertNotRecycled(); final float width = readFloat(); final float height = readFloat(); return new SizeF(width, height); @@ -3806,7 +3624,6 @@ public final class Parcel { */ @Nullable public final byte[] createByteArray() { - assertNotRecycled(); return nativeCreateByteArray(mNativePtr); } @@ -3815,7 +3632,6 @@ public final class Parcel { * given byte array. */ public final void readByteArray(@NonNull byte[] val) { - assertNotRecycled(); boolean valid = nativeReadByteArray(mNativePtr, val, (val != null) ? val.length : 0); if (!valid) { throw new RuntimeException("bad array lengths"); @@ -3828,7 +3644,6 @@ public final class Parcel { */ @Nullable public final byte[] readBlob() { - assertNotRecycled(); return nativeReadBlob(mNativePtr); } @@ -3839,7 +3654,6 @@ public final class Parcel { @UnsupportedAppUsage @Nullable public final String[] readStringArray() { - assertNotRecycled(); return createString16Array(); } @@ -3849,7 +3663,6 @@ public final class Parcel { */ @Nullable public final CharSequence[] readCharSequenceArray() { - assertNotRecycled(); CharSequence[] array = null; int length = readInt(); @@ -3872,7 +3685,6 @@ public final class Parcel { */ @Nullable public final ArrayList<CharSequence> readCharSequenceList() { - assertNotRecycled(); ArrayList<CharSequence> array = null; int length = readInt(); @@ -3902,7 +3714,6 @@ public final class Parcel { @Deprecated @Nullable public ArrayList readArrayList(@Nullable ClassLoader loader) { - assertNotRecycled(); return readArrayListInternal(loader, /* clazz */ null); } @@ -3925,7 +3736,6 @@ public final class Parcel { @Nullable public <T> ArrayList<T> readArrayList(@Nullable ClassLoader loader, @NonNull Class<? extends T> clazz) { - assertNotRecycled(); Objects.requireNonNull(clazz); return readArrayListInternal(loader, clazz); } @@ -3945,7 +3755,6 @@ public final class Parcel { @Deprecated @Nullable public Object[] readArray(@Nullable ClassLoader loader) { - assertNotRecycled(); return readArrayInternal(loader, /* clazz */ null); } @@ -3967,7 +3776,6 @@ public final class Parcel { @SuppressLint({"ArrayReturn", "NullableCollection"}) @Nullable public <T> T[] readArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { - assertNotRecycled(); Objects.requireNonNull(clazz); return readArrayInternal(loader, clazz); } @@ -3987,7 +3795,6 @@ public final class Parcel { @Deprecated @Nullable public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader) { - assertNotRecycled(); return readSparseArrayInternal(loader, /* clazz */ null); } @@ -4009,7 +3816,6 @@ public final class Parcel { @Nullable public <T> SparseArray<T> readSparseArray(@Nullable ClassLoader loader, @NonNull Class<? extends T> clazz) { - assertNotRecycled(); Objects.requireNonNull(clazz); return readSparseArrayInternal(loader, clazz); } @@ -4021,7 +3827,6 @@ public final class Parcel { */ @Nullable public final SparseBooleanArray readSparseBooleanArray() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4038,7 +3843,6 @@ public final class Parcel { */ @Nullable public final SparseIntArray readSparseIntArray() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4063,7 +3867,6 @@ public final class Parcel { */ @Nullable public final <T> ArrayList<T> createTypedArrayList(@NonNull Parcelable.Creator<T> c) { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4087,7 +3890,6 @@ public final class Parcel { * @see #writeTypedList */ public final <T> void readTypedList(@NonNull List<T> list, @NonNull Parcelable.Creator<T> c) { - assertNotRecycled(); int M = list.size(); int N = readInt(); int i = 0; @@ -4117,7 +3919,6 @@ public final class Parcel { */ public final @Nullable <T extends Parcelable> SparseArray<T> createTypedSparseArray( @NonNull Parcelable.Creator<T> creator) { - assertNotRecycled(); final int count = readInt(); if (count < 0) { return null; @@ -4147,7 +3948,6 @@ public final class Parcel { */ public final @Nullable <T extends Parcelable> ArrayMap<String, T> createTypedArrayMap( @NonNull Parcelable.Creator<T> creator) { - assertNotRecycled(); final int count = readInt(); if (count < 0) { return null; @@ -4175,7 +3975,6 @@ public final class Parcel { */ @Nullable public final ArrayList<String> createStringArrayList() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4202,7 +4001,6 @@ public final class Parcel { */ @Nullable public final ArrayList<IBinder> createBinderArrayList() { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4230,7 +4028,6 @@ public final class Parcel { @Nullable public final <T extends IInterface> ArrayList<T> createInterfaceArrayList( @NonNull Function<IBinder, T> asInterface) { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4251,7 +4048,6 @@ public final class Parcel { * @see #writeStringList */ public final void readStringList(@NonNull List<String> list) { - assertNotRecycled(); int M = list.size(); int N = readInt(); int i = 0; @@ -4273,7 +4069,6 @@ public final class Parcel { * @see #writeBinderList */ public final void readBinderList(@NonNull List<IBinder> list) { - assertNotRecycled(); int M = list.size(); int N = readInt(); int i = 0; @@ -4296,7 +4091,6 @@ public final class Parcel { */ public final <T extends IInterface> void readInterfaceList(@NonNull List<T> list, @NonNull Function<IBinder, T> asInterface) { - assertNotRecycled(); int M = list.size(); int N = readInt(); int i = 0; @@ -4328,7 +4122,6 @@ public final class Parcel { @NonNull public final <T extends Parcelable> List<T> readParcelableList(@NonNull List<T> list, @Nullable ClassLoader cl) { - assertNotRecycled(); return readParcelableListInternal(list, cl, /*clazz*/ null); } @@ -4350,7 +4143,6 @@ public final class Parcel { @NonNull public <T> List<T> readParcelableList(@NonNull List<T> list, @Nullable ClassLoader cl, @NonNull Class<? extends T> clazz) { - assertNotRecycled(); Objects.requireNonNull(list); Objects.requireNonNull(clazz); return readParcelableListInternal(list, cl, clazz); @@ -4396,7 +4188,6 @@ public final class Parcel { */ @Nullable public final <T> T[] createTypedArray(@NonNull Parcelable.Creator<T> c) { - assertNotRecycled(); int N = readInt(); if (N < 0) { return null; @@ -4410,7 +4201,6 @@ public final class Parcel { } public final <T> void readTypedArray(@NonNull T[] val, @NonNull Parcelable.Creator<T> c) { - assertNotRecycled(); int N = readInt(); if (N == val.length) { for (int i=0; i<N; i++) { @@ -4427,7 +4217,6 @@ public final class Parcel { */ @Deprecated public final <T> T[] readTypedArray(Parcelable.Creator<T> c) { - assertNotRecycled(); return createTypedArray(c); } @@ -4444,7 +4233,6 @@ public final class Parcel { */ @Nullable public final <T> T readTypedObject(@NonNull Parcelable.Creator<T> c) { - assertNotRecycled(); if (readInt() != 0) { return c.createFromParcel(this); } else { @@ -4471,7 +4259,6 @@ public final class Parcel { * @see #readTypedArray */ public <T> void readFixedArray(@NonNull T val) { - assertNotRecycled(); Class<?> componentType = val.getClass().getComponentType(); if (componentType == boolean.class) { readBooleanArray((boolean[]) val); @@ -4512,7 +4299,6 @@ public final class Parcel { */ public <T, S extends IInterface> void readFixedArray(@NonNull T val, @NonNull Function<IBinder, S> asInterface) { - assertNotRecycled(); Class<?> componentType = val.getClass().getComponentType(); if (IInterface.class.isAssignableFrom(componentType)) { readInterfaceArray((S[]) val, asInterface); @@ -4539,7 +4325,6 @@ public final class Parcel { */ public <T, S extends Parcelable> void readFixedArray(@NonNull T val, @NonNull Parcelable.Creator<S> c) { - assertNotRecycled(); Class<?> componentType = val.getClass().getComponentType(); if (Parcelable.class.isAssignableFrom(componentType)) { readTypedArray((S[]) val, c); @@ -4597,7 +4382,6 @@ public final class Parcel { */ @Nullable public <T> T createFixedArray(@NonNull Class<T> cls, @NonNull int... dimensions) { - assertNotRecycled(); // Check if type matches with dimensions // If type is one-dimensional array, delegate to other creators // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray @@ -4671,7 +4455,6 @@ public final class Parcel { @Nullable public <T, S extends IInterface> T createFixedArray(@NonNull Class<T> cls, @NonNull Function<IBinder, S> asInterface, @NonNull int... dimensions) { - assertNotRecycled(); // Check if type matches with dimensions // If type is one-dimensional array, delegate to other creators // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray @@ -4732,7 +4515,6 @@ public final class Parcel { @Nullable public <T, S extends Parcelable> T createFixedArray(@NonNull Class<T> cls, @NonNull Parcelable.Creator<S> c, @NonNull int... dimensions) { - assertNotRecycled(); // Check if type matches with dimensions // If type is one-dimensional array, delegate to other creators // Otherwise, create an multi-dimensional array at once and then fill it with readFixedArray @@ -4796,7 +4578,6 @@ public final class Parcel { */ public final <T extends Parcelable> void writeParcelableArray(@Nullable T[] value, int parcelableFlags) { - assertNotRecycled(); if (value != null) { int N = value.length; writeInt(N); @@ -4815,7 +4596,6 @@ public final class Parcel { */ @Nullable public final Object readValue(@Nullable ClassLoader loader) { - assertNotRecycled(); return readValue(loader, /* clazz */ null); } @@ -4871,7 +4651,6 @@ public final class Parcel { */ @Nullable public Object readLazyValue(@Nullable ClassLoader loader) { - assertNotRecycled(); int start = dataPosition(); int type = readInt(); if (isLengthPrefixed(type)) { @@ -5274,7 +5053,6 @@ public final class Parcel { @Deprecated @Nullable public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) { - assertNotRecycled(); return readParcelableInternal(loader, /* clazz */ null); } @@ -5294,7 +5072,6 @@ public final class Parcel { */ @Nullable public <T> T readParcelable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { - assertNotRecycled(); Objects.requireNonNull(clazz); return readParcelableInternal(loader, clazz); } @@ -5323,7 +5100,6 @@ public final class Parcel { @Nullable public final <T extends Parcelable> T readCreator(@NonNull Parcelable.Creator<?> creator, @Nullable ClassLoader loader) { - assertNotRecycled(); if (creator instanceof Parcelable.ClassLoaderCreator<?>) { Parcelable.ClassLoaderCreator<?> classLoaderCreator = (Parcelable.ClassLoaderCreator<?>) creator; @@ -5351,7 +5127,6 @@ public final class Parcel { @Deprecated @Nullable public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) { - assertNotRecycled(); return readParcelableCreatorInternal(loader, /* clazz */ null); } @@ -5372,7 +5147,6 @@ public final class Parcel { @Nullable public <T> Parcelable.Creator<T> readParcelableCreator( @Nullable ClassLoader loader, @NonNull Class<T> clazz) { - assertNotRecycled(); Objects.requireNonNull(clazz); return readParcelableCreatorInternal(loader, clazz); } @@ -5495,7 +5269,6 @@ public final class Parcel { @Deprecated @Nullable public Parcelable[] readParcelableArray(@Nullable ClassLoader loader) { - assertNotRecycled(); return readParcelableArrayInternal(loader, /* clazz */ null); } @@ -5516,7 +5289,6 @@ public final class Parcel { @SuppressLint({"ArrayReturn", "NullableCollection"}) @Nullable public <T> T[] readParcelableArray(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { - assertNotRecycled(); return readParcelableArrayInternal(loader, requireNonNull(clazz)); } @@ -5550,7 +5322,6 @@ public final class Parcel { @Deprecated @Nullable public Serializable readSerializable() { - assertNotRecycled(); return readSerializableInternal(/* loader */ null, /* clazz */ null); } @@ -5567,7 +5338,6 @@ public final class Parcel { */ @Nullable public <T> T readSerializable(@Nullable ClassLoader loader, @NonNull Class<T> clazz) { - assertNotRecycled(); Objects.requireNonNull(clazz); return readSerializableInternal( loader == null ? getClass().getClassLoader() : loader, clazz); @@ -5809,7 +5579,6 @@ public final class Parcel { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void readArrayMap(@NonNull ArrayMap<? super String, Object> outVal, @Nullable ClassLoader loader) { - assertNotRecycled(); final int N = readInt(); if (N < 0) { return; @@ -5826,7 +5595,6 @@ public final class Parcel { */ @UnsupportedAppUsage public @Nullable ArraySet<? extends Object> readArraySet(@Nullable ClassLoader loader) { - assertNotRecycled(); final int size = readInt(); if (size < 0) { return null; @@ -5966,7 +5734,6 @@ public final class Parcel { * @hide For testing */ public long getOpenAshmemSize() { - assertNotRecycled(); return nativeGetOpenAshmemSize(mNativePtr); } diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java index e673e17c66ee..6431f3ce73f3 100644 --- a/core/java/android/os/TestLooperManager.java +++ b/core/java/android/os/TestLooperManager.java @@ -123,6 +123,18 @@ public class TestLooperManager { } /** + * Checks whether the Looper is currently blocked on a sync barrier. + * + * A Looper is blocked on a sync barrier if there is a Message in the Looper's + * queue that is ready for execution but is behind a sync barrier + */ + @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY) + public boolean isBlockedOnSyncBarrier() { + checkReleased(); + return mQueue.isBlockedOnSyncBarrier(); + } + + /** * Releases the looper to continue standard looping and processing of messages, no further * interactions with TestLooperManager will be allowed after release() has been called. */ diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 2c4883f1f61c..aacc6e2a3156 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -492,3 +492,13 @@ flag { description: "This flag is used to enable the role system_vendor_intelligence" bug: "377553620" } + +flag { + name: "fine_power_monitor_permission" + is_fixed_read_only: true + is_exported: true + namespace: "permissions" + description: "Add support for fine-grained PowerMonitor readings" + bug: "341941666" +} + diff --git a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java index 64a3f0f60f96..568a6d7cb923 100644 --- a/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java +++ b/core/java/android/security/authenticationpolicy/DisableSecureLockDeviceParams.java @@ -38,23 +38,30 @@ public final class DisableSecureLockDeviceParams implements Parcelable { /** * Client message associated with the request to disable secure lock on the device. This message * will be shown on the device when secure lock mode is disabled. + * + * Since this text is shown in a restricted lockscreen state, typeface properties such as color, + * font weight, or other formatting may not be honored. */ - private final @NonNull String mMessage; + private final @NonNull CharSequence mMessage; /** * Creates DisableSecureLockDeviceParams with the given params. * * @param message Allows clients to pass in a message with information about the request to * disable secure lock on the device. This message will be shown to the user when - * secure lock mode is disabled. If an empty string is provided, it will default - * to a system-defined string (e.g. "Secure lock mode has been disabled.") + * secure lock mode is disabled. If an empty CharSequence is provided, it will + * default to a system-defined CharSequence (e.g. "Secure lock mode has been + * disabled.") + * + * Since this text is shown in a restricted lockscreen state, typeface properties + * such as color, font weight, or other formatting may not be honored. */ - public DisableSecureLockDeviceParams(@NonNull String message) { + public DisableSecureLockDeviceParams(@NonNull CharSequence message) { mMessage = message; } private DisableSecureLockDeviceParams(@NonNull Parcel in) { - mMessage = Objects.requireNonNull(in.readString8()); + mMessage = Objects.requireNonNull(in.readCharSequence()); } public static final @NonNull Creator<DisableSecureLockDeviceParams> CREATOR = @@ -77,6 +84,6 @@ public final class DisableSecureLockDeviceParams implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString8(mMessage); + dest.writeCharSequence(mMessage); } } diff --git a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java index 1d727727ce37..dfa391fcc85d 100644 --- a/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java +++ b/core/java/android/security/authenticationpolicy/EnableSecureLockDeviceParams.java @@ -38,23 +38,30 @@ public final class EnableSecureLockDeviceParams implements Parcelable { /** * Client message associated with the request to enable secure lock on the device. This message * will be shown on the device when secure lock mode is enabled. + * + * Since this text is shown in a restricted lockscreen state, typeface properties such as color, + * font weight, or other formatting may not be honored. */ - private final @NonNull String mMessage; + private final @NonNull CharSequence mMessage; /** * Creates EnableSecureLockDeviceParams with the given params. * * @param message Allows clients to pass in a message with information about the request to * enable secure lock on the device. This message will be shown to the user when - * secure lock mode is enabled. If an empty string is provided, it will default - * to a system-defined string (e.g. "Device is securely locked remotely.") + * secure lock mode is enabled. If an empty CharSequence is provided, it will + * default to a system-defined CharSequence (e.g. "Device is securely locked + * remotely.") + * + * Since this text is shown in a restricted lockscreen state, typeface properties + * such as color, font weight, or other formatting may not be honored. */ - public EnableSecureLockDeviceParams(@NonNull String message) { + public EnableSecureLockDeviceParams(@NonNull CharSequence message) { mMessage = message; } private EnableSecureLockDeviceParams(@NonNull Parcel in) { - mMessage = Objects.requireNonNull(in.readString8()); + mMessage = Objects.requireNonNull(in.readCharSequence()); } public static final @NonNull Creator<EnableSecureLockDeviceParams> CREATOR = @@ -77,6 +84,6 @@ public final class EnableSecureLockDeviceParams implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString8(mMessage); + dest.writeCharSequence(mMessage); } } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 5da49857dda5..072a037aa84a 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -933,6 +933,27 @@ interface IWindowManager void detachWindowContext(IBinder clientToken); /** + * Reparents the {@link android.window.WindowContext} to the + * {@link com.android.server.wm.DisplayArea} on another display. + * This method also reparent the WindowContext associated WindowToken to another display if + * necessary. + * <p> + * {@code type} and {@code options} must be the same as the previous call of + * {@link #attachWindowContextToDisplayArea} on the same Context otherwise this will fail + * silently. + * + * @param appThread the process that the window context is on. + * @param clientToken the window context's token + * @param type The window type of the WindowContext + * @param displayId The new display id this context windows should be parented to + * @param options Bundle the context was created with + * + * @return True if the operation was successful, False otherwise. + */ + boolean reparentWindowContextToDisplayArea(in IApplicationThread appThread, + IBinder clientToken, int displayId); + + /** * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled. * * @param listener the listener to be registered diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 67050e01b591..213ece09da22 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -296,8 +296,8 @@ public class InsetsState implements Parcelable { @SoftInputModeFlags int softInputMode, int windowFlags) { final int softInputAdjustMode = softInputMode & SOFT_INPUT_MASK_ADJUST; final int visibleInsetsTypes = softInputAdjustMode != SOFT_INPUT_ADJUST_NOTHING - ? systemBars() | ime() - : systemBars(); + ? systemBars() | displayCutout() | ime() + : systemBars() | displayCutout(); @InsetsType int forceConsumingTypes = 0; Insets insets = Insets.NONE; for (int i = mSources.size() - 1; i >= 0; i--) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0681745a0fc6..d15b0f518f83 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -17184,7 +17184,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final WindowManager windowManager = mContext.getSystemService(WindowManager.class); final WindowMetrics metrics = windowManager.getMaximumWindowMetrics(); final Insets insets = metrics.getWindowInsets().getInsets( - WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout()); + WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout()); outRect.set(metrics.getBounds()); outRect.inset(insets); outRect.offsetTo(0, 0); diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 1de0474182dd..60e528c5fb58 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -26,6 +26,7 @@ import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG; import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE; import static android.service.autofill.Flags.FLAG_FILL_DIALOG_IMPROVEMENTS; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.service.autofill.Flags.relayoutFix; import static android.view.ContentInfo.SOURCE_AUTOFILL; import static android.view.autofill.Helper.sDebug; @@ -787,6 +788,11 @@ public final class AutofillManager { private AutofillStateFingerprint mAutofillStateFingerprint; + /** + * Whether improveFillDialog feature is enabled or not. + */ + private boolean mImproveFillDialogEnabled; + /** @hide */ public interface AutofillClient { /** @@ -1017,6 +1023,17 @@ public final class AutofillManager { mRelayoutFix = relayoutFix() && AutofillFeatureFlags.enableRelayoutFixes(); mRelativePositionForRelayout = AutofillFeatureFlags.enableRelativeLocationForRelayout(); mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration(); + mImproveFillDialogEnabled = + improveFillDialogAconfig() && AutofillFeatureFlags.isImproveFillDialogEnabled(); + } + + /** + * Whether improvement to fill dialog is enabled. + * + * @hide + */ + public boolean isImproveFillDialogEnabled() { + return mImproveFillDialogEnabled; } /** @@ -1679,6 +1696,11 @@ public final class AutofillManager { private void notifyViewReadyInner(AutofillId id, @Nullable String[] autofillHints, boolean isCredmanRequested) { + if (isImproveFillDialogEnabled() && !isCredmanRequested) { + // We do not want to send pre-trigger request. + // TODO(b/377868687): verify if we can remove the flow for isCredmanRequested too. + return; + } if (sDebug) { Log.d(TAG, "notifyViewReadyInner:" + id); } @@ -2046,6 +2068,34 @@ public final class AutofillManager { } /** + * Notify autofill system that IME animation has started + * @param startTimeMs start time as measured by SystemClock.elapsedRealtime() + */ + void notifyImeAnimationStart(long startTimeMs) { + try { + mService.notifyImeAnimationStart(mSessionId, startTimeMs, mContext.getUserId()); + } catch (RemoteException e) { + // The failure could be a consequence of something going wrong on the + // server side. Just log the exception and move-on. + Log.w(TAG, "notifyImeAnimationStart(): RemoteException caught but ignored " + e); + } + } + + /** + * Notify autofill system that IME animation has ended + * @param endTimeMs end time as measured by SystemClock.elapsedRealtime() + */ + void notifyImeAnimationEnd(long endTimeMs) { + try { + mService.notifyImeAnimationEnd(mSessionId, endTimeMs, mContext.getUserId()); + } catch (RemoteException e) { + // The failure could be a consequence of something going wrong on the + // server side. Just log the exception and move-on. + Log.w(TAG, "notifyImeAnimationStart(): RemoteException caught but ignored " + e); + } + } + + /** * Called when a virtual view that supports autofill is exited. * * @param view the virtual view parent. @@ -4050,6 +4100,10 @@ public final class AutofillManager { @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS) @Deprecated public boolean showAutofillDialog(@NonNull View view) { + if (isImproveFillDialogEnabled()) { + Log.i(TAG, "showAutofillDialog() return false due to improve fill dialog"); + return false; + } Objects.requireNonNull(view); if (shouldShowAutofillDialog(view, view.getAutofillId())) { mShowAutofillDialogCalled = true; @@ -4093,6 +4147,10 @@ public final class AutofillManager { @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS) @Deprecated public boolean showAutofillDialog(@NonNull View view, int virtualId) { + if (isImproveFillDialogEnabled()) { + Log.i(TAG, "showAutofillDialog() return false due to improve fill dialog"); + return false; + } Objects.requireNonNull(view); if (shouldShowAutofillDialog(view, getAutofillId(view, virtualId))) { mShowAutofillDialogCalled = true; @@ -4117,7 +4175,7 @@ public final class AutofillManager { return false; } - if (getImeStateFlag(view) == FLAG_IME_SHOWING) { + if (getImeStateFlag(view) == FLAG_IME_SHOWING && !isImproveFillDialogEnabled()) { // IME is showing return false; } diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index f67405f7c1e4..28f8577beed7 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -70,4 +70,6 @@ oneway interface IAutoFillManager { void notifyNotExpiringResponseDuringAuth(int sessionId, int userId); void notifyViewEnteredIgnoredDuringAuthCount(int sessionId, int userId); void setAutofillIdsAttemptedForRefill(int sessionId, in List<AutofillId> ids, int userId); + void notifyImeAnimationStart(int sessionId, long startTimeMs, int userId); + void notifyImeAnimationEnd(int sessionId, long endTimeMs, int userId); } diff --git a/core/java/android/view/flags/scroll_capture.aconfig b/core/java/android/view/flags/scroll_capture.aconfig index 9080b1669ed5..6dccbad3b6a9 100644 --- a/core/java/android/view/flags/scroll_capture.aconfig +++ b/core/java/android/view/flags/scroll_capture.aconfig @@ -11,3 +11,12 @@ flag { } } +flag { + name: "scroll_capture_relax_scroll_view_criteria" + namespace: "systemui" + description: "Treat all custom ViewGroups which support scrollTo as ScrollView" + bug: "189827634" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java index b606340b77a7..b9293242e4ff 100644 --- a/core/java/android/view/textclassifier/TextClassificationManager.java +++ b/core/java/android/view/textclassifier/TextClassificationManager.java @@ -16,13 +16,20 @@ package android.view.textclassifier; +import static android.Manifest.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE; + +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Build; import android.os.ServiceManager; +import android.permission.flags.Flags; import android.view.textclassifier.TextClassifier.TextClassifierType; import com.android.internal.annotations.GuardedBy; @@ -115,6 +122,29 @@ public final class TextClassificationManager { } } + /** + * Returns a specific type of text classifier. + * If the specified text classifier cannot be found, this returns {@link TextClassifier#NO_OP}. + * <p> + * + * @see TextClassifier#CLASSIFIER_TYPE_SELF_PROVIDED + * @see TextClassifier#CLASSIFIER_TYPE_DEVICE_DEFAULT + * @see TextClassifier#CLASSIFIER_TYPE_ANDROID_DEFAULT + * @hide + */ + @SystemApi + @NonNull + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + @RequiresPermission(ACCESS_TEXT_CLASSIFIER_BY_TYPE) + public TextClassifier getClassifier(@TextClassifierType int type) { + if (mContext.checkCallingOrSelfPermission(ACCESS_TEXT_CLASSIFIER_BY_TYPE) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Caller does not have permission " + ACCESS_TEXT_CLASSIFIER_BY_TYPE); + } + return getTextClassifier(type); + } + private TextClassificationConstants getSettings() { synchronized (mLock) { if (mSettings == null) { diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java index ef5004536354..59afdac1bfd7 100644 --- a/core/java/android/view/textclassifier/TextClassifier.java +++ b/core/java/android/view/textclassifier/TextClassifier.java @@ -16,16 +16,20 @@ package android.view.textclassifier; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.WorkerThread; import android.os.LocaleList; import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; +import android.permission.flags.Flags; import android.text.Spannable; import android.text.SpannableString; import android.text.style.URLSpan; @@ -63,11 +67,6 @@ public interface TextClassifier { /** @hide */ String LOG_TAG = "androidtc"; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = {LOCAL, SYSTEM, DEFAULT_SYSTEM}) - @interface TextClassifierType {} // TODO: Expose as system APIs. /** Specifies a TextClassifier that runs locally in the app's process. @hide */ int LOCAL = 0; /** Specifies a TextClassifier that runs in the system process and serves all apps. @hide */ @@ -76,8 +75,33 @@ public interface TextClassifier { int DEFAULT_SYSTEM = 2; /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = {CLASSIFIER_TYPE_SELF_PROVIDED, CLASSIFIER_TYPE_DEVICE_DEFAULT, + CLASSIFIER_TYPE_ANDROID_DEFAULT}) + @interface TextClassifierType { + } + /** Specifies a TextClassifier that runs locally in the app's process. @hide */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + @SystemApi + int CLASSIFIER_TYPE_SELF_PROVIDED = LOCAL; + /** + * Specifies a TextClassifier that is set as the default on this particular device. This may be + * the same as CLASSIFIER_TYPE_DEVICE_DEFAULT, unless set otherwise by the device manufacturer. + * @hide + */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + @SystemApi + int CLASSIFIER_TYPE_DEVICE_DEFAULT = SYSTEM; + /** Specifies the TextClassifier that is provided by Android. @hide */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + @SystemApi + int CLASSIFIER_TYPE_ANDROID_DEFAULT = DEFAULT_SYSTEM; + + /** @hide */ + @SuppressLint("SwitchIntDef") static String typeToString(@TextClassifierType int type) { - switch (type) { + int unflaggedType = type; + switch (unflaggedType) { case LOCAL: return "Local"; case SYSTEM: @@ -108,6 +132,9 @@ public interface TextClassifier { String TYPE_DATE_TIME = "datetime"; /** Flight number in IATA format. */ String TYPE_FLIGHT_NUMBER = "flight"; + /** Onetime password. */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + String TYPE_OTP = "otp"; /** * Word that users may be interested to look up for meaning. * @hide @@ -126,7 +153,8 @@ public interface TextClassifier { TYPE_DATE, TYPE_DATE_TIME, TYPE_FLIGHT_NUMBER, - TYPE_DICTIONARY + TYPE_DICTIONARY, + TYPE_OTP }) @interface EntityType {} @@ -198,6 +226,16 @@ public interface TextClassifier { String EXTRA_FROM_TEXT_CLASSIFIER = "android.view.textclassifier.extra.FROM_TEXT_CLASSIFIER"; /** + * Extra specifying the package name of the app from which the text to be classified originated. + * + * For example, a notification assistant might use TextClassifier, but the notification + * content could originate from a different app. This key allows you to provide + * the package name of that source app. + */ + @FlaggedApi(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + String EXTRA_TEXT_ORIGIN_PACKAGE = "android.view.textclassifier.extra.TEXT_ORIGIN_PACKAGE"; + + /** * Returns suggested text selection start and end indices, recognized entity types, and their * associated confidence scores. The entity types are ordered from highest to lowest scoring. * diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 0721fd379e9b..fc3014a0eaec 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3737,7 +3737,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te atEdge = trackMotionScroll(deltaY, incrementalDeltaY); // TODO: b/360198915 - Add unit testing for using ScrollFeedbackProvider - if (enableScrollFeedbackForTouch()) { + if (vtev != null && enableScrollFeedbackForTouch()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollProgress( vtev.getDeviceId(), vtev.getSource(), MotionEvent.AXIS_Y, @@ -3779,7 +3779,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mTouchMode = TOUCH_MODE_OVERSCROLL; } - if (enableScrollFeedbackForTouch()) { + if (vtev != null && enableScrollFeedbackForTouch()) { initHapticScrollFeedbackProviderIfNotExists(); mHapticScrollFeedbackProvider.onScrollLimit( vtev.getDeviceId(), vtev.getSource(), diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d7750bd412a3..71a832d84f08 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -18,6 +18,7 @@ package android.widget; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static android.graphics.Paint.NEW_FONT_VARIATION_MANAGEMENT; import static android.view.ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT; import static android.view.ContentInfo.SOURCE_AUTOFILL; import static android.view.ContentInfo.SOURCE_CLIPBOARD; @@ -5542,7 +5543,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener && fontVariationSettings.equals(existingSettings))) { return true; } - boolean effective = mTextPaint.setFontVariationSettings(fontVariationSettings); + + final boolean useFontVariationStore = Flags.typefaceRedesignReadonly() + && CompatChanges.isChangeEnabled(NEW_FONT_VARIATION_MANAGEMENT); + boolean effective; + if (useFontVariationStore) { + if (mFontWeightAdjustment != 0 + && mFontWeightAdjustment != Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED) { + mTextPaint.setFontVariationSettings(fontVariationSettings, mFontWeightAdjustment); + } else { + mTextPaint.setFontVariationSettings(fontVariationSettings); + } + effective = true; + } else { + effective = mTextPaint.setFontVariationSettings(fontVariationSettings); + } if (effective && mLayout != null) { nullLayouts(); @@ -10114,6 +10129,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener outAttrs.extras.putBoolean( STYLUS_HANDWRITING_ENABLED_ANDROIDX_EXTRAS_KEY, handwritingEnabled); } + if (android.view.inputmethod.Flags.writingTools()) { + // default to same behavior as isSuggestionsEnabled(). + outAttrs.setWritingToolsEnabled(isSuggestionsEnabled()); + } ArrayList<Class<? extends HandwritingGesture>> gestures = new ArrayList<>(); gestures.add(SelectGesture.class); gestures.add(SelectRangeGesture.class); diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java index 2b370b9797e5..84a8b8f5b5b0 100644 --- a/core/java/android/window/WindowContext.java +++ b/core/java/android/window/WindowContext.java @@ -32,6 +32,7 @@ import android.view.Display; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.window.flags.Flags; import java.lang.ref.Reference; @@ -95,20 +96,20 @@ public class WindowContext extends ContextWrapper implements WindowProvider { } /** - * Updates this context to a new displayId. + * Moves this context to another display. * <p> - * Note that this doesn't re-parent previously attached windows (they should be removed and - * re-added manually after this is called). Resources associated with this context will have - * the correct value and configuration for the new display after this is called. + * Note that this re-parents all the previously attached windows. Resources associated with this + * context will have the correct value and configuration for the new display after this is + * called. */ - @Override - public void updateDisplay(int displayId) { - if (displayId == getDisplayId()) { - return; + public void reparentToDisplay(int displayId) { + if (Flags.reparentWindowTokenApi()) { + if (displayId == getDisplayId()) { + return; + } + super.updateDisplay(displayId); + mController.reparentToDisplayArea(mType, displayId, mOptions); } - super.updateDisplay(displayId); - mController.detachIfNeeded(); - mController.attachToDisplayArea(mType, displayId, mOptions); } @Override diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java index c9ac245bc36f..1e2f454adeef 100644 --- a/core/java/android/window/WindowContextController.java +++ b/core/java/android/window/WindowContextController.java @@ -158,6 +158,21 @@ public class WindowContextController { } } + /** + * Reparents the window context from the current attached display to another. {@code type} and + * {@code options} must be the same as the previous attach call, otherwise this will fail + * silently. + */ + public void reparentToDisplayArea( + @WindowType int type, int displayId, @Nullable Bundle options) { + if (mAttachedToDisplayArea != AttachStatus.STATUS_ATTACHED) { + attachToDisplayArea(type, displayId, options); + return; + } + // No need to propagate type and options as this is already attached and they can't change. + getWindowTokenClientController().reparentToDisplayArea(mToken, displayId); + } + /** Gets the {@link WindowTokenClientController}. */ @VisibleForTesting @NonNull diff --git a/core/java/android/window/WindowTokenClientController.java b/core/java/android/window/WindowTokenClientController.java index fa345956ec4d..1ec05b65861d 100644 --- a/core/java/android/window/WindowTokenClientController.java +++ b/core/java/android/window/WindowTokenClientController.java @@ -197,6 +197,21 @@ public class WindowTokenClientController { } } + /** + * Reparents a {@link WindowTokenClient} and its associated WindowContainer if there's one. + */ + public void reparentToDisplayArea(@NonNull WindowTokenClient client, int displayId) { + try { + if (!getWindowManagerService().reparentWindowContextToDisplayArea(mAppThread, client, + displayId)) { + Log.e(TAG, + "Didn't succeed reparenting of " + client + " to displayId=" + displayId); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private void onWindowContextTokenAttached(@NonNull WindowTokenClient client, @NonNull WindowContextInfo info, boolean shouldReportConfigChange) { recordWindowContextToken(client); diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index f01aa80fab4f..2cfc680a3fe8 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -163,5 +163,4 @@ interface IAppOpsService { void finishOperationForDevice(IBinder clientId, int code, int uid, String packageName, @nullable String attributionTag, int virtualDeviceId); List<AppOpsManager.PackageOps> getPackagesForOpsForDevice(in int[] ops, String persistentDeviceId); - oneway void noteOperationsInBatch(in Map batchedNoteOps); } diff --git a/core/java/com/android/internal/policy/KeyInterceptionInfo.java b/core/java/com/android/internal/policy/KeyInterceptionInfo.java index b20f6d225b69..fed8fe3b4cc0 100644 --- a/core/java/com/android/internal/policy/KeyInterceptionInfo.java +++ b/core/java/com/android/internal/policy/KeyInterceptionInfo.java @@ -27,11 +27,13 @@ public class KeyInterceptionInfo { // Debug friendly name to help identify the window public final String windowTitle; public final int windowOwnerUid; + public final int inputFeaturesFlags; - public KeyInterceptionInfo(int type, int flags, String title, int uid) { + public KeyInterceptionInfo(int type, int flags, String title, int uid, int inputFeaturesFlags) { layoutParamsType = type; layoutParamsPrivateFlags = flags; windowTitle = title; windowOwnerUid = uid; + this.inputFeaturesFlags = inputFeaturesFlags; } } diff --git a/core/java/com/android/internal/view/ScrollCaptureInternal.java b/core/java/com/android/internal/view/ScrollCaptureInternal.java index 72b5488f4bac..0ed0613d02e6 100644 --- a/core/java/com/android/internal/view/ScrollCaptureInternal.java +++ b/core/java/com/android/internal/view/ScrollCaptureInternal.java @@ -16,6 +16,8 @@ package com.android.internal.view; +import static android.view.flags.Flags.scrollCaptureRelaxScrollViewCriteria; + import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; @@ -49,7 +51,7 @@ public class ScrollCaptureInternal { public static final int TYPE_FIXED = 0; /** - * Slides a single child view using mScrollX/mScrollY. + * Moves the viewport across absolute positioned child views using the scrollY property. */ public static final int TYPE_SCROLLING = 1; @@ -63,7 +65,7 @@ public class ScrollCaptureInternal { /** * Unknown scrollable view with no child views (or not a subclass of ViewGroup). */ - private static final int TYPE_OPAQUE = 3; + public static final int TYPE_OPAQUE = 3; /** * Performs tests on the given View and determines: @@ -73,7 +75,7 @@ public class ScrollCaptureInternal { * This needs to be fast and not alloc memory. It's called on everything in the tree not marked * as excluded during scroll capture search. */ - private static int detectScrollingType(View view) { + public static int detectScrollingType(View view) { // Confirm that it can scroll. if (!(view.canScrollVertically(DOWN) || view.canScrollVertically(UP))) { // Nothing to scroll here, move along. @@ -95,25 +97,25 @@ public class ScrollCaptureInternal { if (DEBUG_VERBOSE) { Log.v(TAG, "hint: is a subclass of ViewGroup"); } - - // ScrollViews accept only a single child. - if (((ViewGroup) view).getChildCount() > 1) { - if (DEBUG_VERBOSE) { - Log.v(TAG, "hint: scrollable with multiple children"); + // Flag: Optionally allow ScrollView-like ViewGroups which have more than one child view. + if (!scrollCaptureRelaxScrollViewCriteria()) { + // ScrollViews accept only a single child. + if (((ViewGroup) view).getChildCount() > 1) { + if (DEBUG_VERBOSE) { + Log.v(TAG, "hint: scrollable with multiple children"); + } + return TYPE_RECYCLING; } - return TYPE_RECYCLING; } // At least one child view is required. - if (((ViewGroup) view).getChildCount() < 1) { - if (DEBUG_VERBOSE) { - Log.v(TAG, "scrollable with no children"); - } + if (((ViewGroup) view).getChildCount() == 0) { + Log.w(TAG, "scrollable but no children!"); return TYPE_OPAQUE; } if (DEBUG_VERBOSE) { Log.v(TAG, "hint: single child view"); } - //Because recycling containers don't use scrollY, a non-zero value means Scroll view. + // Because recycling containers don't use scrollY, a non-zero value means Scroll view. if (view.getScrollY() != 0) { if (DEBUG_VERBOSE) { Log.v(TAG, "hint: scrollY != 0"); @@ -132,7 +134,7 @@ public class ScrollCaptureInternal { Log.v(TAG, "hint: cannot be scrolled up"); } - // canScrollVertically(UP) == false, getScrollY() == 0, getChildCount() == 1. + // canScrollVertically(UP) == false, getScrollY() == 0, getChildCount() >= 1. // For Recycling containers, this should be a no-op (RecyclerView logs a warning) view.scrollTo(view.getScrollX(), 1); diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java index 1e9ba78e52c5..33f93fccff58 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -699,6 +699,7 @@ public class CoreDocument { } op.markNotDirty(); op.apply(context); + context.incrementOpCount(); } } @@ -1000,6 +1001,16 @@ public class CoreDocument { private final float[] mScaleOutput = new float[2]; private final float[] mTranslateOutput = new float[2]; private int mRepaintNext = -1; // delay to next repaint -1 = don't 1 = asap + private int mLastOpCount; + + /** + * This is the number of ops used to calculate the last frame. + * + * @return number of ops + */ + public int getOpsPerFrame() { + return mLastOpCount; + } /** * Returns > 0 if it needs to repaint @@ -1017,6 +1028,7 @@ public class CoreDocument { * @param theme the theme we want to use for this document. */ public void paint(@NonNull RemoteContext context, int theme) { + context.getLastOpCount(); context.getPaintContext().clearNeedsRepaint(); context.loadFloat(RemoteContext.ID_DENSITY, context.getDensity()); context.mMode = RemoteContext.ContextMode.UNSET; @@ -1027,21 +1039,24 @@ public class CoreDocument { context.mRemoteComposeState = mRemoteComposeState; context.mRemoteComposeState.setContext(context); + // If we have a content sizing set, we are going to take the original document + // dimension into account and apply scale+translate according to the RootContentBehavior + // rules. if (mContentSizing == RootContentBehavior.SIZING_SCALE) { // we need to add canvas transforms ops here computeScale(context.mWidth, context.mHeight, mScaleOutput); - computeTranslate( - context.mWidth, - context.mHeight, - mScaleOutput[0], - mScaleOutput[1], - mTranslateOutput); + float sw = mScaleOutput[0]; + float sh = mScaleOutput[1]; + computeTranslate(context.mWidth, context.mHeight, sw, sh, mTranslateOutput); context.mPaintContext.translate(mTranslateOutput[0], mTranslateOutput[1]); - context.mPaintContext.scale(mScaleOutput[0], mScaleOutput[1]); + context.mPaintContext.scale(sw, sh); + } else { + // If not, we set the document width and height to be the current context width and + // height. + setWidth((int) context.mWidth); + setHeight((int) context.mHeight); } mTimeVariables.updateTime(context); - context.loadFloat(RemoteContext.ID_WINDOW_WIDTH, context.mWidth); - context.loadFloat(RemoteContext.ID_WINDOW_HEIGHT, context.mHeight); mRepaintNext = context.updateOps(); if (mRootLayoutComponent != null) { if (context.mWidth != mRootLayoutComponent.getWidth() @@ -1051,11 +1066,11 @@ public class CoreDocument { if (mRootLayoutComponent.needsMeasure()) { mRootLayoutComponent.layout(context); } - // TODO -- this should be specifically about applying animation, not paint - mRootLayoutComponent.paint(context.getPaintContext()); - context.mPaintContext.reset(); - // TODO -- should be able to remove this - mRootLayoutComponent.updateVariables(context); + if (mRootLayoutComponent.needsBoundsAnimation()) { + mRepaintNext = 1; + mRootLayoutComponent.clearNeedsBoundsAnimation(); + mRootLayoutComponent.animatingBounds(context); + } if (DEBUG) { String hierarchy = mRootLayoutComponent.displayHierarchy(); System.out.println(hierarchy); @@ -1081,6 +1096,7 @@ public class CoreDocument { op.markNotDirty(); ((VariableSupport) op).updateVariables(context); } + context.incrementOpCount(); op.apply(context); } } @@ -1093,6 +1109,38 @@ public class CoreDocument { if (DEBUG && mRootLayoutComponent != null) { System.out.println(mRootLayoutComponent.displayHierarchy()); } + mLastOpCount = context.getLastOpCount(); + } + + /** + * Get an estimated number of operations executed in a paint + * + * @return number of operations + */ + public int getNumberOfOps() { + int count = mOperations.size(); + + for (Operation mOperation : mOperations) { + if (mOperation instanceof Component) { + count += getChildOps((Component) mOperation); + } + } + return count; + } + + private int getChildOps(@NonNull Component base) { + int count = base.mList.size(); + for (Operation mOperation : base.mList) { + + if (mOperation instanceof Component) { + int mult = 1; + if (mOperation instanceof LoopOperation) { + mult = ((LoopOperation) mOperation).estimateIterations(); + } + count += mult * getChildOps((Component) mOperation); + } + } + return count; } @NonNull @@ -1116,6 +1164,9 @@ public class CoreDocument { if (mOperation instanceof Component) { Component com = (Component) mOperation; count += addChildren(com, map, buffer); + } else if (mOperation instanceof LoopOperation) { + LoopOperation com = (LoopOperation) mOperation; + count += addChildren(com, map, buffer); } } @@ -1153,6 +1204,35 @@ public class CoreDocument { if (mOperation instanceof Component) { count += addChildren((Component) mOperation, map, tmp); } + if (mOperation instanceof LoopOperation) { + count += addChildren((LoopOperation) mOperation, map, tmp); + } + } + return count; + } + + private int addChildren( + @NonNull LoopOperation base, + @NonNull HashMap<String, int[]> map, + @NonNull WireBuffer tmp) { + int count = base.mList.size(); + for (Operation mOperation : base.mList) { + Class<? extends Operation> c = mOperation.getClass(); + int[] values; + if (map.containsKey(c.getSimpleName())) { + values = map.get(c.getSimpleName()); + } else { + values = new int[2]; + map.put(c.getSimpleName(), values); + } + values[0] += 1; + values[1] += sizeOfComponent(mOperation, tmp); + if (mOperation instanceof Component) { + count += addChildren((Component) mOperation, map, tmp); + } + if (mOperation instanceof LoopOperation) { + count += addChildren((LoopOperation) mOperation, map, tmp); + } } return count; } @@ -1198,7 +1278,6 @@ public class CoreDocument { * @param ctl the call back to allow evaluation of shaders */ public void checkShaders(RemoteContext context, ShaderControl ctl) { - int count = 0; for (Operation op : mOperations) { if (op instanceof TextData) { op.apply(context); diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java index c03f44bfc162..b5587ce095a2 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java @@ -40,6 +40,7 @@ import java.time.ZoneOffset; * <p>We also contain a PaintContext, so that any operation can draw as needed. */ public abstract class RemoteContext { + private static final int MAX_OP_COUNT = 100_000; // Maximum cmds per frame protected @NonNull CoreDocument mDocument = new CoreDocument(); // todo: is this a valid way to initialize? bbade@ public @NonNull RemoteComposeState mRemoteComposeState = @@ -52,6 +53,7 @@ public abstract class RemoteContext { int mDebug = 0; + private int mOpCount; private int mTheme = Theme.UNSPECIFIED; public float mWidth = 0f; @@ -631,4 +633,23 @@ public abstract class RemoteContext { float right, float bottom, int metadataId); + + /** increments the count of operations executed in a pass */ + public void incrementOpCount() { + mOpCount++; + if (mOpCount > MAX_OP_COUNT) { + throw new RuntimeException("Too many operations executed"); + } + } + + /** + * Get the last Op Count and clear the count. + * + * @return the number of ops executed. + */ + public int getLastOpCount() { + int count = mOpCount; + mOpCount = 0; + return count; + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java index cd7ebec67a46..ea917db98e65 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java +++ b/core/java/com/android/internal/widget/remotecompose/core/TimeVariables.java @@ -24,7 +24,7 @@ import java.time.ZoneOffset; /** This generates the standard system variables for time. */ public class TimeVariables { - private static final float BUILD = 0.01f; + private static final float BUILD = 0.02f; /** * This class populates all time variables in the system diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java index dcf1d250b2f5..e05bdf2b824d 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ClickModifierOperation.java @@ -106,6 +106,7 @@ public class ClickModifierOperation extends PaintOperation for (Operation op : mList) { if (op instanceof TextData) { op.apply(context); + context.incrementOpCount(); } } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java index e95dfdaa4cf9..8a77dc3aafa5 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/Component.java @@ -66,6 +66,34 @@ public class Component extends PaintOperation implements Measurable, Serializabl protected float mZIndex = 0f; + private boolean mNeedsBoundsAnimation = false; + + /** + * Mark the component as needing a bounds animation pass + */ + public void markNeedsBoundsAnimation() { + mNeedsBoundsAnimation = true; + if (mParent != null && !mParent.mNeedsBoundsAnimation) { + mParent.markNeedsBoundsAnimation(); + } + } + + /** + * Clear the bounds animation pass flag + */ + public void clearNeedsBoundsAnimation() { + mNeedsBoundsAnimation = false; + } + + /** + * True if needs a bounds animation + * + * @return true if needs a bounds animation pass + */ + public boolean needsBoundsAnimation() { + return mNeedsBoundsAnimation; + } + public float getZIndex() { return mZIndex; } @@ -382,12 +410,40 @@ public class Component extends PaintOperation implements Measurable, Serializabl } else { mVisibility = m.getVisibility(); } - setWidth(m.getW()); - setHeight(m.getH()); - setLayoutPosition(m.getX(), m.getY()); + if (mAnimateMeasure == null) { + setWidth(m.getW()); + setHeight(m.getH()); + setLayoutPosition(m.getX(), m.getY()); + updateComponentValues(context); + clearNeedsBoundsAnimation(); + } else { + mAnimateMeasure.apply(context); + updateComponentValues(context); + markNeedsBoundsAnimation(); + } mFirstLayout = false; } + /** + * Animate the bounds of the component as needed + * @param context + */ + public void animatingBounds(@NonNull RemoteContext context) { + if (mAnimateMeasure != null) { + mAnimateMeasure.apply(context); + updateComponentValues(context); + markNeedsBoundsAnimation(); + } else { + clearNeedsBoundsAnimation(); + } + for (Operation op : mList) { + if (op instanceof Measurable) { + Measurable m = (Measurable) op; + m.animatingBounds(context); + } + } + } + @NonNull public float[] locationInWindow = new float[2]; public boolean contains(float x, float y) { @@ -698,9 +754,6 @@ public class Component extends PaintOperation implements Measurable, Serializabl } public void paintingComponent(@NonNull PaintContext context) { - if (!mComponentValues.isEmpty()) { - updateComponentValues(context.getContext()); - } if (mPreTranslate != null) { mPreTranslate.paint(context); } @@ -718,8 +771,10 @@ public class Component extends PaintOperation implements Measurable, Serializabl } if (op instanceof PaintOperation) { ((PaintOperation) op).paint(context); + context.getContext().incrementOpCount(); } else { op.apply(context.getContext()); + context.getContext().incrementOpCount(); } } context.restore(); @@ -728,7 +783,7 @@ public class Component extends PaintOperation implements Measurable, Serializabl public boolean applyAnimationAsNeeded(@NonNull PaintContext context) { if (context.isAnimationEnabled() && mAnimateMeasure != null) { - mAnimateMeasure.apply(context); + mAnimateMeasure.paint(context); context.needsRepaint(); return true; } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java index e25392c5d2ff..91038852573e 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LayoutComponent.java @@ -286,7 +286,9 @@ public class LayoutComponent extends Component { @Override public void paintingComponent(@NonNull PaintContext context) { Component prev = context.getContext().mLastComponent; - context.getContext().mLastComponent = this; + RemoteContext remoteContext = context.getContext(); + + remoteContext.mLastComponent = this; context.save(); context.translate(mX, mY); if (context.isVisualDebug()) { @@ -329,6 +331,7 @@ public class LayoutComponent extends Component { child.updateVariables(context.getContext()); child.markNotDirty(); } + remoteContext.incrementOpCount(); child.paint(context); } } else { @@ -337,6 +340,7 @@ public class LayoutComponent extends Component { child.updateVariables(context.getContext()); child.markNotDirty(); } + remoteContext.incrementOpCount(); child.paint(context); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java index 505656e212f1..9fc5da8320ba 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/ListActionsOperation.java @@ -57,6 +57,7 @@ public abstract class ListActionsOperation extends PaintOperation for (Operation op : mList) { if (op instanceof TextData) { op.apply(context); + context.incrementOpCount(); } } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java index 1b85681bcc08..ab1e0ac73368 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/LoopOperation.java @@ -107,9 +107,11 @@ public class LoopOperation extends PaintOperation implements VariableSupport { @Override public void paint(@NonNull PaintContext context) { + RemoteContext remoteContext = context.getContext(); if (mIndexVariableId == 0) { for (float i = mFromOut; i < mUntilOut; i += mStepOut) { for (Operation op : mList) { + remoteContext.incrementOpCount(); op.apply(context.getContext()); } } @@ -120,6 +122,7 @@ public class LoopOperation extends PaintOperation implements VariableSupport { if (op instanceof VariableSupport && op.isDirty()) { ((VariableSupport) op).updateVariables(context.getContext()); } + remoteContext.incrementOpCount(); op.apply(context.getContext()); } } @@ -172,4 +175,16 @@ public class LoopOperation extends PaintOperation implements VariableSupport { .field(DocumentedOperation.FLOAT, "step", "value step") .field(DocumentedOperation.FLOAT, "until", "stops less than or equal"); } + + /** + * Calculate and estimate of the number of iterations + * + * @return number of loops or 10 if based on variables + */ + public int estimateIterations() { + if (!(Float.isNaN(mUntil) || Float.isNaN(mFrom) || Float.isNaN(mStep))) { + return (int) (0.5f + (mUntil - mFrom) / mStep); + } + return 10; // this is a generic estmate if the values are variables; + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java index 11c0f3f394f5..11fa7ee670dd 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/RootLayoutComponent.java @@ -137,8 +137,8 @@ public class RootLayoutComponent extends Component implements ComponentStartOper return; } context.mLastComponent = this; - mWidth = context.mWidth; - mHeight = context.mHeight; + setWidth(context.mWidth); + setHeight(context.mHeight); // TODO: reuse MeasurePass MeasurePass measurePass = new MeasurePass(); @@ -155,7 +155,9 @@ public class RootLayoutComponent extends Component implements ComponentStartOper @Override public void paint(@NonNull PaintContext context) { mNeedsRepaint = false; - context.getContext().mLastComponent = this; + RemoteContext remoteContext = context.getContext(); + remoteContext.mLastComponent = this; + context.save(); if (mParent == null) { // root layout @@ -165,6 +167,7 @@ public class RootLayoutComponent extends Component implements ComponentStartOper for (Operation op : mList) { if (op instanceof PaintOperation) { ((PaintOperation) op).paint(context); + remoteContext.incrementOpCount(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java index 2af3c739035c..1de956b7e5d7 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/animation/AnimateMeasure.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import com.android.internal.widget.remotecompose.core.Operation; import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; import com.android.internal.widget.remotecompose.core.operations.layout.Component; import com.android.internal.widget.remotecompose.core.operations.layout.DecoratorComponent; import com.android.internal.widget.remotecompose.core.operations.layout.measure.ComponentMeasure; @@ -103,13 +104,18 @@ public class AnimateMeasure { @NonNull public PaintBundle paint = new PaintBundle(); - public void apply(@NonNull PaintContext context) { - update(context.getContext().currentTime); - + /** + * Apply the layout portion of the animation if any + * + * @param context + */ + public void apply(@NonNull RemoteContext context) { + update(context.currentTime); mComponent.setX(getX()); mComponent.setY(getY()); mComponent.setWidth(getWidth()); mComponent.setHeight(getHeight()); + mComponent.updateVariables(context); float w = mComponent.getWidth(); float h = mComponent.getHeight(); @@ -120,10 +126,17 @@ public class AnimateMeasure { h -= pop.getTop() + pop.getBottom(); } if (op instanceof DecoratorComponent) { - ((DecoratorComponent) op).layout(context.getContext(), mComponent, w, h); + ((DecoratorComponent) op).layout(context, mComponent, w, h); } } + } + /** + * Paint the transition animation for the component owned + * + * @param context + */ + public void paint(@NonNull PaintContext context) { if (mOriginal.getVisibility() != mTarget.getVisibility()) { if (mTarget.getVisibility() == Component.Visibility.GONE) { switch (mExitAnimation) { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java index fbf2784be843..a9998745a5d6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/measure/Measurable.java @@ -44,4 +44,11 @@ public interface Measurable { * @return true if need to remeasured, false otherwise */ boolean needsMeasure(); + + /** + * Animate bounds of the component + * + * @param context + */ + void animatingBounds(RemoteContext context); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java index d2ba13f69a91..a1609ace2138 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/layout/modifiers/ComponentModifiers.java @@ -49,6 +49,7 @@ public class ComponentModifiers extends PaintOperation super.apply(context); for (ModifierOperation op : mList) { op.apply(context); + context.incrementOpCount(); } } diff --git a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java index 7dad2931c97f..6eb83f1da410 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java +++ b/core/java/com/android/internal/widget/remotecompose/player/RemoteComposePlayer.java @@ -250,8 +250,23 @@ public class RemoteComposePlayer extends FrameLayout { mInner.clearLocalString("SYSTEM:" + name); } + /** + * This is the number of ops used to calculate the last frame. + * + * @return number of ops + */ + public int getOpsPerFrame() { + return mInner.getDocument().mDocument.getOpsPerFrame(); + } + /** Id action callback interface */ public interface IdActionCallbacks { + /** + * Callback for on action + * + * @param id the id of the action + * @param metadata the metadata of the action + */ void onAction(int id, String metadata); } diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp index 805d5ad41e83..cd39e6f93fb4 100644 --- a/core/jni/android_os_SELinux.cpp +++ b/core/jni/android_os_SELinux.cpp @@ -34,23 +34,27 @@ namespace android { namespace { -std::atomic<selabel_handle*> sehandle{nullptr}; +std::atomic<selabel_handle *> file_sehandle{nullptr}; -selabel_handle* GetSELabelHandle() { - selabel_handle* h = sehandle.load(); +selabel_handle *GetSELabelHandle_impl(selabel_handle *(*handle_func)(), + std::atomic<selabel_handle *> *handle_cache) { + selabel_handle *h = handle_cache->load(); if (h != nullptr) { return h; } - h = selinux_android_file_context_handle(); + h = handle_func(); selabel_handle* expected = nullptr; - if (!sehandle.compare_exchange_strong(expected, h)) { + if (!handle_cache->compare_exchange_strong(expected, h)) { selabel_close(h); - return sehandle.load(); + return handle_cache->load(); } return h; } +selabel_handle *GetSELabelFileBackendHandle() { + return GetSELabelHandle_impl(selinux_android_file_context_handle, &file_sehandle); +} } struct SecurityContext_Delete { @@ -106,7 +110,7 @@ static jstring fileSelabelLookup(JNIEnv* env, jobject, jstring pathStr) { return NULL; } - auto* selabel_handle = GetSELabelHandle(); + auto *selabel_handle = GetSELabelFileBackendHandle(); if (selabel_handle == NULL) { ALOGE("fileSelabelLookup => Failed to get SEHandle"); return NULL; diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index b2eeff36c007..f40cfd9f8e51 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -532,7 +532,12 @@ static inline bool app_compat_16kb_enabled() { static const size_t kPageSize = getpagesize(); // App compat is only applicable on 16kb-page-size devices. - return kPageSize == 0x4000; + if (kPageSize != 0x4000) { + return false; + } + + // Explicit disabled status for app compat + return !android::base::GetBoolProperty("pm.16kb.app_compat.disabled", false); } static jint diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 6b0569041edd..6b8056c77fda 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -6853,6 +6853,13 @@ <permission android:name="android.permission.BATTERY_STATS" android:protectionLevel="signature|privileged|development" /> + <!-- @SystemApi @hide Allows an application to collect high-precision PowerMonitor readings + <p>Protection level: signature|privileged|development + @FlaggedApi(android.permission.flags.Flags.FLAG_FINE_POWER_MONITOR_PERMISSION) --> + <permission android:name="android.permission.ACCESS_FINE_POWER_MONITORS" + android:protectionLevel="signature|privileged|development" + android:featureFlag="android.permission.flags.fine_power_monitor_permission" /> + <!--Allows an application to manage statscompanion. <p>Not for use by third-party applications. @hide --> @@ -8792,6 +8799,17 @@ android:protectionLevel="signature|privileged|vendorPrivileged" android:featureFlag="android.media.tv.flags.kids_mode_tvdb_sharing"/> + <!-- @SystemApi + @FlaggedApi("android.permission.flags.text_classifier_choice_api_enabled") + This permission is required to access the specific text classifier you need from the + TextClassificationManager. + <p>Protection level: signature|role + @hide + --> + <permission android:name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE" + android:protectionLevel="signature|role" + android:featureFlag="android.permission.flags.text_classifier_choice_api_enabled"/> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index edb926c5a30c..c02c13cca79c 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -369,13 +369,13 @@ <string name="permlab_statusBar" msgid="8798267849526214017">"deaktiveer of verander statusbalk"</string> <string name="permdesc_statusBar" msgid="5809162768651019642">"Laat die app toe om die statusbalk te deaktiveer en stelselikone by te voeg of te verwyder."</string> <string name="permlab_statusBarService" msgid="2523421018081437981">"wees die statusbalk"</string> - <string name="permdesc_statusBarService" msgid="6652917399085712557">"Laat die program toe om die statusbalk te wees."</string> + <string name="permdesc_statusBarService" msgid="6652917399085712557">"Laat die app toe om die statusbalk te wees."</string> <string name="permlab_expandStatusBar" msgid="1184232794782141698">"vou statusbalk in of uit"</string> <string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Laat die program toe om die statusbalk uit te vou of in te vou."</string> <string name="permlab_fullScreenIntent" msgid="4310888199502509104">"wys kennisgewings as volskermaktiwiteite op \'n geslote skerm"</string> <string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Laat die program toe om kennisgewings as volskermaktiwiteite op \'n geslote toestel te wys"</string> <string name="permlab_install_shortcut" msgid="7451554307502256221">"installeer kortpaaie"</string> - <string name="permdesc_install_shortcut" msgid="4476328467240212503">"Stel \'n program in staat om Tuisskerm-kortpaaie by te voeg sonder gebruikerinmenging."</string> + <string name="permdesc_install_shortcut" msgid="4476328467240212503">"Stel \'n app in staat om Tuisskerm-kortpaaie by te voeg sonder gebruikerinmenging."</string> <string name="permlab_uninstall_shortcut" msgid="295263654781900390">"deïnstalleer kortpaaie"</string> <string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Laat die app toe om Tuisskerm-kortpaaie te verwyder sonder gebruikerinmenging."</string> <string name="permlab_processOutgoingCalls" msgid="4075056020714266558">"herlei uitgaande oproepe"</string> @@ -387,17 +387,17 @@ <string name="permlab_receiveMms" msgid="4000650116674380275">"ontvang teksboodskappe (MMS)"</string> <string name="permdesc_receiveMms" msgid="958102423732219710">"Laat die program toe om MMS-boodskappe te ontvang en te verwerk. Dit beteken dat die program boodskappe wat na jou toestel gestuur is kan monitor of uitvee, sonder dat jy dit gesien het."</string> <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"Stuur seluitsendingboodskappe aan"</string> - <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Laat die program toe om die seluitsendingmodule te bind om seluitsendingboodskappe aan te stuur wanneer hulle ontvang word. Seluitsendingwaarskuwings word in sommige liggings gelewer om jou oor noodsituasies te waarsku. Kwaadwillige programme kan met die werkverrigting of werking van jou toestel inmeng wanneer \'n noodseluitsending ontvang word."</string> + <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Laat die app toe om aan die seluitsendingmodule te bind om seluitsendingboodskappe aan te stuur wanneer hulle ontvang word. Seluitsendingwaarskuwings word in sommige liggings gelewer om jou oor noodsituasies te waarsku. Kwaadwillige apps kan met die werkverrigting of werking van jou toestel inmeng wanneer \'n noodseluitsending ontvang word."</string> <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Bestuur voortgaande oproepe"</string> <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Stel \'n program in staat om besonderhede oor voortgaande oproepe op jou toestel te sien, en hierdie oproepe te beheer."</string> <string name="permlab_accessLastKnownCellId" msgid="7638226620825665130">"Kry toegang tot laaste bekende selidentiteit."</string> <string name="permdesc_accessLastKnownCellId" msgid="6664621339249308857">"Laat ’n app toe om toegang tot die laaste bekende selidentiteit te kry wat deur telefonie verskaf is"</string> <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lees seluitsending-boodskappe"</string> - <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Laat die program toe om seluitsending-boodskappe te lees wat deur jou toestel ontvang word. Seluitsending-waarskuwings word in sommige plekke afgelewer om jou van noodsituasies te waarsku. Kwaadwillige programme mag inmeng met die prestasie of die werking van jou toestel wanneer \'n noodgeval se seluitsending ontvang word."</string> + <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Laat die app toe om seluitsending-boodskappe te lees wat deur jou toestel ontvang word. Seluitsending-waarskuwings word in sommige plekke afgelewer om jou van noodsituasies te waarsku. Kwaadwillige apps kan inmeng met die prestasie of die werking van jou toestel wanneer \'n noodgeval se seluitsending ontvang word."</string> <string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lees ingetekende nuus"</string> - <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Laat die program toe om details oor die tans gesinkroniseerde strome te kry."</string> + <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Laat die app toe om details oor die tans gesinkroniseerde strome te kry."</string> <string name="permlab_sendSms" msgid="7757368721742014252">"SMS-boodskappe te stuur en te bekyk"</string> - <string name="permdesc_sendSms" msgid="6757089798435130769">"Laat die program toe om SMS-boodskappe te stuur. Dit kan tot onverwagse heffings lei. Kwaadwillige programme kan jou geld kos deur boodskappe sonder jou bevestiging te stuur."</string> + <string name="permdesc_sendSms" msgid="6757089798435130769">"Laat die app toe om SMS-boodskappe te stuur. Dit kan tot onverwagse heffings lei. Kwaadwillige apps kan jou geld kos deur boodskappe sonder jou bevestiging te stuur."</string> <string name="permlab_readSms" msgid="5164176626258800297">"lees jou teksboodskappe (SMS of MMS)"</string> <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"Hierdie program kan alle SMS\'e (teksboodskappe) wat op jou tablet geberg is, lees."</string> <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"Hierdie app kan alle SMS- (teks)-boodskappe lees wat op jou Android TV-toestel geberg is."</string> @@ -411,24 +411,24 @@ <string name="permlab_reorderTasks" msgid="7598562301992923804">"herrangskik lopende programme"</string> <string name="permdesc_reorderTasks" msgid="8796089937352344183">"Laat die program toe om take na die voorgrond of agtergrond te skuif. Die program kan dit moontlik sonder jou insette doen."</string> <string name="permlab_enableCarMode" msgid="893019409519325311">"aktiveer motormodus"</string> - <string name="permdesc_enableCarMode" msgid="56419168820473508">"Laat die program toe om die motormodus te aktiveer."</string> + <string name="permdesc_enableCarMode" msgid="56419168820473508">"Laat die app toe om die motormodus te aktiveer."</string> <string name="permlab_killBackgroundProcesses" msgid="6559320515561928348">"maak ander programme toe"</string> <string name="permdesc_killBackgroundProcesses" msgid="2357013583055434685">"Laat die app toe om agtergrondprosesse van ander apps te beëindig. Dit kan moontlik veroorsaak dat ander apps ophou werk."</string> - <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"Hierdie program kan bo-op ander programme verskyn"</string> + <string name="permlab_systemAlertWindow" msgid="5757218350944719065">"Hierdie app kan bo-op ander apps verskyn"</string> <string name="permdesc_systemAlertWindow" msgid="1145660714855738308">"Hierdie app kan bokant ander apps of ander dele van die skerm verskyn. Dit kan met normale appgebruik inmeng en die voorkoms van ander apps verander."</string> <string name="permlab_hideOverlayWindows" msgid="6382697828482271802">"versteek ander apps se oorleggers"</string> <string name="permdesc_hideOverlayWindows" msgid="5660242821651958225">"Hierdie app kan versoek dat die stelsel oorleggers wat oorspronklik van apps af kom, versteek sodat hulle nie bo-op hulle wys nie."</string> <string name="permlab_runInBackground" msgid="541863968571682785">"loop op die agtergrond"</string> - <string name="permdesc_runInBackground" msgid="4344539472115495141">"Hierdie program kan op die agtergrond loop. Dit kan die battery vinniger laat pap word."</string> + <string name="permdesc_runInBackground" msgid="4344539472115495141">"Hierdie app kan op die agtergrond loop. Dit kan die battery vinniger laat pap word."</string> <string name="permlab_useDataInBackground" msgid="783415807623038947">"gebruik data op die agtergrond"</string> <string name="permdesc_useDataInBackground" msgid="1230753883865891987">"Hierdie app kan data op die agtergrond gebruik. Dit kan die datagebruik vergroot."</string> <string name="permlab_schedule_exact_alarm" msgid="6683283918033029730">"Skeduleer handelinge met presiese tydsbesturing"</string> <string name="permdesc_schedule_exact_alarm" msgid="8198009212013211497">"Hierdie app kan werk skeduleer om op ’n gewenste tyd in die toekoms plaas te vind. Dit beteken ook dat die app kan werk wanneer die toestel nie aktief gebruik word nie."</string> <string name="permlab_use_exact_alarm" msgid="348045139777131552">"Skeduleer wekkers of geleentheidonthounotas"</string> <string name="permdesc_use_exact_alarm" msgid="7033761461886938912">"Hierdie app kan handelinge soos wekkers en onthounotas skeduleer om jou op ’n gewenste tyd in die toekoms in kennis te stel."</string> - <string name="permlab_persistentActivity" msgid="464970041740567970">"laat program altyd loop"</string> - <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"Laat die program toe om dele van ditself deurdringend in die geheue te hou. Dit kan geheue wat aan ander programme beskikbaar is, beperk, en die tablet stadiger maak."</string> - <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"Laat die program toe om dele daarvan in die geheue te laat voortbestaan. Dit kan geheue wat vir ander programme beskikbaar is, beperk en sodoende jou Android TV-toestel stadiger maak."</string> + <string name="permlab_persistentActivity" msgid="464970041740567970">"laat app altyd loop"</string> + <string name="permdesc_persistentActivity" product="tablet" msgid="6055271149187369916">"Laat die app toe om dele van die app deurdringend in die geheue te hou. Dit kan geheue wat aan ander apps beskikbaar is, beperk, en die tablet stadiger maak."</string> + <string name="permdesc_persistentActivity" product="tv" msgid="6800526387664131321">"Laat die app toe om dele daarvan in die geheue te laat voortbestaan. Dit kan geheue wat vir ander apps beskikbaar is, beperk en sodoende jou Android TV-toestel stadiger maak."</string> <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Laat die app toe om dele van die app deurdringend in die geheue te hou. Dit kan geheue wat aan ander apps beskikbaar is, beperk, en die foon stadiger maak."</string> <string name="permlab_foregroundService" msgid="1768855976818467491">"laat loop voorgronddiens"</string> <string name="permdesc_foregroundService" msgid="8720071450020922795">"Laat die program toe om van voorgronddienste gebruik te maak."</string> @@ -465,8 +465,8 @@ <string name="permlab_writeSettings" msgid="8057285063719277394">"verander stelsel-instellings"</string> <string name="permdesc_writeSettings" msgid="8293047411196067188">"Laat die program toe om die stelsel se instellingsdata te verander. Kwaadwillige programme kan dalk jou stelsel se opstelling korrupteer."</string> <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"laat loop wanneer begin"</string> - <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"Laat die program toe om homself te begin so gou as moontlik nadat die stelsel laai. Dit maak dat dit langer neem vir die tablet om te begin, en dit laat die foon toe om die tablet stadiger te maak omdat dit altyd loop."</string> - <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"Laat die program toe om self te begin sodra die stelsel klaar geselflaai het. Dit kan dalk daartoe lei dat die toestel langer neem om jou Android TV-toestel te begin, en laat die program toe om die hele toestel stadiger te maak deur altyd te loop."</string> + <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"Laat die app toe om self te begin sodra die stelsel geselflaai het. Dit maak dat dit langer neem vir die tablet om te begin, en dit laat die foon toe om die tablet stadiger te maak omdat dit altyd loop."</string> + <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"Laat die app toe om self te begin sodra die stelsel klaar geselflaai het. Dit kan dalk daartoe lei dat die toestel langer neem om jou Android TV-toestel te begin, en laat die app toe om die hele toestel stadiger te maak deur altyd te loop."</string> <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"Laat die program toe om homself te begin so gou as moontlik nadat die stelsel laai. Dit maak dat dit langer neem vir die foon om te begin, en dit laat die foon toe om die foon stadiger te maak omdat dit altyd loop."</string> <string name="permlab_broadcastSticky" msgid="4552241916400572230">"Stuur klewerige uitsending"</string> <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"Laat die app toe om vaste uitsendings te stuur, wat agterbly nadat die uitsending klaar is. Oormatige gebruik kan die tablet stadig of onstabiel maak deurdat dit te veel geheue gebruik."</string> @@ -484,20 +484,20 @@ <string name="permdesc_readCallLog" msgid="8964770895425873433">"Hierdie program kan jou oproepgeskiedenis lees."</string> <string name="permlab_writeCallLog" msgid="670292975137658895">"skryf oproeprekord"</string> <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Laat die app toe om jou tablet se oproeprekord, insluitende data oor inkomende en uitgaande oproepe, te verander. Kwaadwillige apps kan dit gebruik om jou oproeprekord uit te vee of te verander."</string> - <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Laat die program toe om jou Android TV-toestel se oproeprekord te wysig, insluitend data oor inkomende en uitgaande oproepe. Kwaadwillige programme kan dit gebruik om jou oproeprekord uit te vee of te wysig."</string> - <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Laat die program toe om jou foon se oproeprekord, insluitende data oor inkomende en uitgaande oproepe, te verander. Kwaadwillige programme kan dit gebruik om jou oproeprekord uit te vee of te verander."</string> - <string name="permlab_bodySensors" msgid="662918578601619569">"Kry toegang tot liggaamsensordata, soos polsslag, terwyl program gebruik word"</string> + <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Laat die app toe om jou Android TV-toestel se oproeprekord te wysig, insluitend data oor inkomende en uitgaande oproepe. Kwaadwillige apps kan dit gebruik om jou oproeprekord uit te vee of te wysig."</string> + <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Laat die app toe om jou foon se oproeprekord, insluitende data oor inkomende en uitgaande oproepe, te verander. Kwaadwillige apps kan dit gebruik om jou oproeprekord uit te vee of te verander."</string> + <string name="permlab_bodySensors" msgid="662918578601619569">"Kry toegang tot liggaamsensordata, soos polsslag, terwyl app gebruik word"</string> <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Gee die app toegang tot liggaamsensordata, soos polsslag, temperatuur en bloedsuurstofpersentasie, terwyl die app gebruik word."</string> - <string name="permlab_bodySensors_background" msgid="4912560779957760446">"Kry toegang tot liggaamsensordata, soos polsslag, terwyl program op agtergrond is"</string> - <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Gee die program toegang tot liggaamsensordata, soos polsslag, temperatuur en bloedsuurstofpersentasie, terwyl dit op die agtergrond is."</string> + <string name="permlab_bodySensors_background" msgid="4912560779957760446">"Kry toegang tot liggaamsensordata, soos polsslag, terwyl app op die agtergrond is"</string> + <string name="permdesc_bodySensors_background" product="default" msgid="8870726027557749417">"Gee die app toegang tot liggaamsensordata, soos polsslag, temperatuur en bloedsuurstofpersentasie, terwyl dit op die agtergrond is."</string> <string name="permlab_readCalendar" msgid="6408654259475396200">"Lees kalendergebeurtenisse en -besonderhede"</string> - <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Hierdie program kan alle kalendergebeurtenisse lees wat op jou tablet geberg is of jou kalenderdata stoor."</string> - <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Hierdie program kan alle kalendergeleenthede wat op jou Android TV-toestel geberg is, lees of jou kalenderdata stoor."</string> + <string name="permdesc_readCalendar" product="tablet" msgid="515452384059803326">"Hierdie app kan alle kalendergebeurtenisse lees wat op jou tablet geberg is of jou kalenderdata stoor."</string> + <string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"Hierdie app kan alle kalendergeleenthede lees wat op jou Android TV-toestel geberg is of jou kalenderdata stoor."</string> <string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"Hierdie program kan alle kalendergebeurtenisse lees wat op jou foon geberg is of jou kalenderdata stoor."</string> <string name="permlab_writeCalendar" msgid="6422137308329578076">"voeg by of verander kalenderafsprake en stuur \'n e-pos aan gaste sonder eienaars se medewete"</string> <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"Hierdie program kan kalendergebeurtenisse op jou tablet byvoeg, verwyder of verander. Hierdie program kan boodskappe stuur wat lyk of dit van kalendereienaars af kom of gebeurtenisse verander sonder om hul eienaars in te lig."</string> <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"Hierdie program kan kalendergeleenthede op jou Android TV-toestel byvoeg, verwyder of verander. Hierdie program kan boodskappe stuur wat lyk of dit van kalendereienaars af kom of geleenthede verander sonder om hul eienaars in kennis te stel."</string> - <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Hierdie program kan kalendergebeurtenisse op jou foon byvoeg, verwyder of verander. Hierdie program kan boodskappe stuur wat lyk of dit van kalendereienaars af kom of gebeurtenisse verander sonder om hul eienaars in te lig."</string> + <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"Hierdie app kan kalendergebeurtenisse op jou foon byvoeg, verwyder of verander. Hierdie app kan boodskappe stuur wat lyk of dit van kalendereienaars af kom of gebeurtenisse verander sonder om hul eienaars in te lig."</string> <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"Kry toegang tot ekstra liggingverskaffer-bevele"</string> <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Gee die app toegang tot ekstra liggingverskaffer-bevele. Dit kan die app dalk toelaat om in te meng met die werking van die GPS of ander liggingbronne."</string> <string name="permlab_accessFineLocation" msgid="6426318438195622966">"kry net op die voorgrond toegang tot presiese ligging"</string> @@ -515,7 +515,7 @@ <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"bespeur skermskote van appvensters"</string> <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Hierdie app sal ingelig word as ’n skermskoot geneem word terwyl die app gebruik word."</string> <string name="permlab_sim_communication" msgid="176788115994050692">"stuur bevele na die SIM"</string> - <string name="permdesc_sim_communication" msgid="4179799296415957960">"Laat die program toe om bevele na die SIM te stuur. Dit is baie gevaarlik."</string> + <string name="permdesc_sim_communication" msgid="4179799296415957960">"Laat die app toe om bevele na die SIM te stuur. Dit is baie gevaarlik."</string> <string name="permlab_activityRecognition" msgid="1782303296053990884">"herken fisieke aktiwiteit"</string> <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Hierdie program kan jou fisieke aktiwiteit herken."</string> <string name="permlab_camera" msgid="6320282492904119413">"neem foto\'s en video\'s"</string> @@ -534,19 +534,19 @@ <string name="permlab_callPhone" msgid="1798582257194643320">"skakel foonnommers direk"</string> <string name="permdesc_callPhone" msgid="7892422187827695656">"Laat die app toe om foonnommers sonder jou insae te bel. Dit kan onvoorsiene heffings of oproepe tot gevolg hê. Neem kennis dat dit nie die app toelaat om noodnommers te bel nie. Kwaadwillige apps kan jou geld kos deur oproepe te maak sonder jou bevestiging of diensverskafferkodes te bel wat veroorsaak dat inkomende oproepe outomaties na ’n ander nommer aangestuur word."</string> <string name="permlab_accessImsCallService" msgid="442192920714863782">"toegang tot kitsboodskapoproepdiens"</string> - <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Laat die program toe om die kitsboodskapdiens te gebruik om oproepe sonder jou ingryping te maak."</string> + <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Laat die app toe om die kitsboodskapdiens te gebruik om oproepe sonder jou ingryping te maak."</string> <string name="permlab_readPhoneState" msgid="8138526903259297969">"lees foonstatus en identiteit"</string> <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Laat die program toe om toegang tot die foonfunksies van die toestel te verkry. Hierdie toestemming laat die program toe om te bepaal wat die foonnommer en toestel-IDs is, of die oproep aan die gang is, en die afgeleë nommer wat deur \'n oproep verbind word."</string> <string name="permlab_readBasicPhoneState" msgid="3214853233263871347">"lees basiese telefoniestatus en -identiteit"</string> <string name="permdesc_readBasicPhoneState" msgid="828185691675460520">"Gee die program toegang tot die toestel se basiese telefoniekenmerke."</string> <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"roeteer oproepe deur die stelsel"</string> - <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Laat die program toe om sy oproepe deur die stelsel te stuur om die oproepervaring te verbeter."</string> + <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Laat die app toe om sy oproepe deur die stelsel te stuur om die oproepervaring te verbeter."</string> <string name="permlab_callCompanionApp" msgid="3654373653014126884">"sien en beheer oproepe deur die stelsel."</string> <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"Laat die program toe om deurlopende oproepe op die toestel te sien en te beheer. Dit sluit inligting in soos oproepnommers vir oproepe en die toedrag van die oproepe."</string> <string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"vrygestel van beperkings op oudio-opnames"</string> <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"Stel die program vry van beperkings om oudio op te neem."</string> <string name="permlab_acceptHandover" msgid="2925523073573116523">"gaan voort met \'n oproep uit \'n ander app"</string> - <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Laat die program toe om \'n oproep voort te sit wat in \'n ander program begin is."</string> + <string name="permdesc_acceptHandovers" msgid="7129026180128626870">"Laat die app toe om \'n oproep voort te sit wat in \'n ander app begin is."</string> <string name="permlab_readPhoneNumbers" msgid="5668704794723365628">"lees foonnommers"</string> <string name="permdesc_readPhoneNumbers" msgid="7368652482818338871">"Laat die program toe om toegang tot die toestel se foonnommers te kry."</string> <string name="permlab_wakeLock" product="automotive" msgid="1904736682319375676">"hou motorskerm aan"</string> @@ -558,7 +558,7 @@ <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Laat die app toe om te keer dat jou Android TV-toestel slaap."</string> <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Laat die app toe om die foon te keer om te slaap."</string> <string name="permlab_transmitIr" msgid="8077196086358004010">"versend infrarooi"</string> - <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Laat die program toe om die tablet se infrarooisender te gebruik."</string> + <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Laat die app toe om die tablet se infrarooisender te gebruik."</string> <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Laat die app toe om jou Android TV-toestel se infrarooisender te gebruik."</string> <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Laat die program toe om die foon se infrarooisender te gebruik."</string> <string name="permlab_setWallpaper" msgid="6959514622698794511">"stel muurpapier"</string> @@ -566,25 +566,25 @@ <string name="permlab_accessHiddenProfile" msgid="8607094418491556823">"Kry toegang tot versteekte profiele"</string> <string name="permdesc_accessHiddenProfile" msgid="1543153202481009676">"Laat die app toe om toegang tot versteekte profiele te kry."</string> <string name="permlab_setWallpaperHints" msgid="1153485176642032714">"verstel jou muurpapier se grootte"</string> - <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"Laat die program toe om die stelsel se muurpapier se groottewenke te stel."</string> + <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"Laat die app toe om die stelsel se muurpapier se groottewenke te stel."</string> <string name="permlab_setTimeZone" msgid="7922618798611542432">"stel tydsone"</string> <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"Laat die app toe om die tablet se tydsone te verander."</string> <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"Laat die program toe om jou Android TV-toestel se tydsone te verander."</string> - <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Laat die program toe om die foon se tydsone te verander."</string> + <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Laat die app toe om die foon se tydsone te verander."</string> <string name="permlab_getAccounts" msgid="5304317160463582791">"soek rekeninge op die toestel"</string> <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Laat die app toe om die lys van rekeninge wat aan die tablet bekend is, te kry. Dit kan moontlik enige rekeninge wat geskep is deur apps wat jy geïnstalleer het, insluit."</string> - <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Laat die program toe om die lys rekeninge wat aan jou Android TV-toestel bekend is, te kry. Dit kan dalk rekeninge insluit wat geskep is deur programme wat jy geïnstalleer het."</string> + <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Laat die app toe om die lys rekeninge wat aan jou Android TV-toestel bekend is, te kry. Dit kan dalk rekeninge insluit wat geskep is deur apps wat jy geïnstalleer het."</string> <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Laat die app toe om die lys van rekeninge wat aan die foon bekend is, te kry. Dit kan moontlik enige rekeninge wat geskep is deur apps wat jy geïnstalleer het, insluit."</string> <string name="permlab_accessNetworkState" msgid="2349126720783633918">"bekyk netwerkverbindings"</string> - <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Laat die program toe om inligting oor netwerkverbindings, soos watter netwerke bestaan en gekoppel is, te sien."</string> + <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Laat die app toe om inligting oor netwerkverbindings, soos watter netwerke bestaan en gekoppel is, te sien."</string> <string name="permlab_createNetworkSockets" msgid="3224420491603590541">"verkry volle netwerktoegang"</string> <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Laat die program toe om netwerksokke te skep en gepasmaakte netwerkprotokolle te gebruik. Die blaaier en ander programme verskaf reeds die middele waardeur data na die internet gestuur kan word, so hierdie toestemming word nie vereis om data na die internet te stuur nie."</string> <string name="permlab_changeNetworkState" msgid="8945711637530425586">"verander netwerkverbinding"</string> - <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Laat die program toe om die status van netwerkkonnektiwiteit te verander."</string> + <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Laat die app toe om die status van netwerkkonnektiwiteit te verander."</string> <string name="permlab_changeTetherState" msgid="9079611809931863861">"verander verbinde konnektiwiteit"</string> <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Laat die app toe om die status van verbinde netwerkkonnektiwiteit te verander."</string> <string name="permlab_accessWifiState" msgid="5552488500317911052">"bekyk Wi-Fi-verbindings"</string> - <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Laat die program toe om inligting oor Wi-Fi-netwerke, soos of Wi-Fi geaktiveer is en die name van gekoppelde Wi-Fi toestelle, te sien."</string> + <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Laat die app toe om inligting oor wi-fi-netwerke, soos of wi-fi geaktiveer is en die name van gekoppelde wi-fi-toestelle, te sien."</string> <string name="permlab_changeWifiState" msgid="7947824109713181554">"koppel en ontkoppel van Wi-Fi"</string> <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Laat die program toe om te koppel aan en te ontkoppel van Wi-Fi-toegangspunte en om veranderings aan Wi-Fi-netwerke se toestelopstellings te maak."</string> <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"laat Wi-Fi-multisendontvangs toe"</string> @@ -592,14 +592,14 @@ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Laat die app toe om pakkette te ontvang wat met multi-uitsendingadresse na alle toestelle op \'n wi-fi-netwerk gestuur is, nie net jou Android TV-toestel nie. Dit gebruik meer krag as nie-multi-uitsendingmodus."</string> <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Laat die program toe om pakkies te ontvang wat met behulp van multisaai-adresse na alle toestelle op \'n Wi-Fi-netwerk gestuur is, nie net jou foon nie. Dit gebruik meer krag as die nie-multisaaimodus."</string> <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"gaan in by Bluetooth-instellings"</string> - <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Laat die program toe om die plaaslike Bluetooth-tablet op te stel, en om met afstandbeheer toestelle saam te bind."</string> + <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Laat die app toe om die plaaslike Bluetooth-tablet op te stel, en om met afstandbeheer toestelle saam te bind."</string> <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Laat die app toe om Bluetooth op jou Android TV-toestel op te stel, en om afgeleë toestelle te ontdek en met hulle saam te bind."</string> <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Laat die program toe om die plaaslike Bluetooth-foon op te stel en te ontdek en met afgeleë toestelle saam te bind."</string> <string name="permlab_accessWimaxState" msgid="7029563339012437434">"koppel aan en ontkoppel van WiMAX"</string> - <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Laat die program toe om te bepaal of WiMAX geaktiveer is en of enige WiMAX-netwerke gekoppel is."</string> + <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Laat die app toe om te bepaal of WiMAX geaktiveer is en of enige WiMAX-netwerke gekoppel is."</string> <string name="permlab_changeWimaxState" msgid="6223305780806267462">"verander WiMAX-status"</string> - <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Laat die program toe om die tablet aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string> - <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Laat die program toe om jou Android TV-toestel aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string> + <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Laat die app toe om die tablet aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string> + <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Laat die app toe om jou Android TV-toestel aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string> <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Laat die app toe om die foon aan WiMAX-netwerke te koppel en daarvan te ontkoppel."</string> <string name="permlab_bluetooth" msgid="586333280736937209">"bind saam met Bluetooth-toestelle"</string> <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Laat die app toe om die opstelling van Bluetooth op die tablet te sien, en om verbindings met saamgebinde toestelle te maak en te aanvaar."</string> @@ -630,21 +630,21 @@ <string name="permlab_postNotification" msgid="4875401198597803658">"wys kennisgewings"</string> <string name="permdesc_postNotification" msgid="5974977162462877075">"Laat die program toe om kennisgewings te wys"</string> <string name="permlab_turnScreenOn" msgid="219344053664171492">"skakel die skerm aan"</string> - <string name="permdesc_turnScreenOn" msgid="4394606875897601559">"Laat die program toe om die skerm aan te skakel."</string> + <string name="permdesc_turnScreenOn" msgid="4394606875897601559">"Laat die app toe om die skerm aan te skakel."</string> <string name="permlab_useBiometric" msgid="6314741124749633786">"gebruik biometriese hardeware"</string> <string name="permdesc_useBiometric" msgid="7502858732677143410">"Laat die program toe om biometriese hardeware vir stawing te gebruik"</string> <string name="permlab_manageFingerprint" msgid="7432667156322821178">"bestuur vingerafdrukhardeware"</string> <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Laat die app toe om metodes te benut om vingerafdruktemplate vir gebruik by te voeg en uit te vee."</string> <string name="permlab_useFingerprint" msgid="1001421069766751922">"gebruik vingerafdrukhardeware"</string> - <string name="permdesc_useFingerprint" msgid="412463055059323742">"Laat die program toe om vingerafdrukhardeware vir stawing te gebruik"</string> + <string name="permdesc_useFingerprint" msgid="412463055059323742">"Laat die app toe om vingerafdrukhardeware vir stawing te gebruik"</string> <string name="permlab_audioWrite" msgid="8501705294265669405">"wysig jou musiekversameling"</string> <string name="permdesc_audioWrite" msgid="8057399517013412431">"Laat die program toe om jou musiekversameling te wysig."</string> <string name="permlab_videoWrite" msgid="5940738769586451318">"wysig jou videoversameling"</string> - <string name="permdesc_videoWrite" msgid="6124731210613317051">"Laat die program toe om jou videoversameling te wysig."</string> + <string name="permdesc_videoWrite" msgid="6124731210613317051">"Laat die app toe om jou videoversameling te wysig."</string> <string name="permlab_imagesWrite" msgid="1774555086984985578">"wysig jou fotoversameling"</string> - <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Laat die program toe om jou fotoversameling te wysig."</string> + <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 program toe om liggings in jou mediaversameling te lees."</string> + <string name="permdesc_mediaLocation" msgid="597912899423578138">"Laat die app toe om liggings in jou mediaversameling te lees."</string> <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> @@ -764,17 +764,17 @@ <string name="permlab_readSyncSettings" msgid="6250532864893156277">"lees sinkroniseer-instellings"</string> <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Laat die app toe om die sinkroniseringinstellings van \'n rekening te lees. Byvoorbeeld, dit kan bepaal of die People-app met \'n rekening gesinkroniseer is."</string> <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"wissel tussen sinkronisasie aan en af"</string> - <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Laat \'n program toe om die sinkroniseringinstellings van \'n rekening te verander. Byvoorbeeld, dit kan gebruik word om sinkronisasie van die People-program met \'n ander rekening te aktiveer."</string> + <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"Laat \'n app toe om die sinkroniseringinstellings van \'n rekening te verander. Byvoorbeeld, dit kan gebruik word om sinkronisasie van die People-app met \'n ander rekening te aktiveer."</string> <string name="permlab_readSyncStats" msgid="3747407238320105332">"lees sinkroniseerstatistiek"</string> - <string name="permdesc_readSyncStats" msgid="3867809926567379434">"Laat \'n program toe om die sinkroniseringstatistieke van \'n rekening te lees, insluitend die geskiedenis van sinkroniseringgebeure en hoeveel data gesinkroniseer is."</string> + <string name="permdesc_readSyncStats" msgid="3867809926567379434">"Laat \'n app toe om die sinkroniseringstatistieke van \'n rekening te lees, insluitend die geskiedenis van sinkroniseringgebeure en hoeveel data gesinkroniseer is."</string> <string name="permlab_sdcardRead" msgid="5791467020950064920">"lees jou gedeelde berging se inhoud"</string> - <string name="permdesc_sdcardRead" msgid="6872973242228240382">"Laat die program toe om jou gedeelde berging se inhoud te lees."</string> + <string name="permdesc_sdcardRead" msgid="6872973242228240382">"Laat die app toe om jou gedeelde berging se inhoud te lees."</string> <string name="permlab_readMediaAudio" msgid="8723513075731763810">"lees oudiolêers in gedeelde berging"</string> - <string name="permdesc_readMediaAudio" msgid="5299772574434619399">"Laat die program toe om oudiolêers in jou gedeelde berging te lees."</string> + <string name="permdesc_readMediaAudio" msgid="5299772574434619399">"Laat die app toe om oudiolêers in jou gedeelde berging te lees."</string> <string name="permlab_readMediaVideo" msgid="7768003311260655007">"lees videolêers in gedeelde berging"</string> - <string name="permdesc_readMediaVideo" msgid="3846400073770403528">"Laat die program toe om videolêers in jou gedeelde berging te lees."</string> + <string name="permdesc_readMediaVideo" msgid="3846400073770403528">"Laat die app toe om videolêers in jou gedeelde berging te lees."</string> <string name="permlab_readMediaImages" msgid="4057590631020986789">"lees prentlêers in gedeelde berging"</string> - <string name="permdesc_readMediaImages" msgid="5836219373138469259">"Laat die program toe om prentlêers in jou gedeelde berging te lees."</string> + <string name="permdesc_readMediaImages" msgid="5836219373138469259">"Laat die app toe om prentlêers in jou gedeelde berging te lees."</string> <string name="permlab_readVisualUserSelect" msgid="5516204215354667586">"lees prent- en videolêers wat gebruiker in gedeelde berging kies"</string> <string name="permdesc_readVisualUserSelect" msgid="8027174717714968217">"Laat die app toe om prent- en videolêers te lees wat jy in jou gedeelde berging kies."</string> <string name="permlab_sdcardWrite" msgid="4863021819671416668">"verander of vee jou gedeelde berging se inhoud uit"</string> @@ -782,23 +782,23 @@ <string name="permlab_use_sip" msgid="8250774565189337477">"maak en/of ontvang SIP-oproepe"</string> <string name="permdesc_use_sip" msgid="3590270893253204451">"Laat die app toe om SIP-oproepe te maak en te ontvang."</string> <string name="permlab_register_sim_subscription" msgid="1653054249287576161">"registreer nuwe telekommunikasie-SIM-verbindings"</string> - <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"Laat die program toe om nuwe telekommunikasie-SIM-verbindings te registreer."</string> + <string name="permdesc_register_sim_subscription" msgid="4183858662792232464">"Laat die app toe om nuwe telekommunikasie-SIM-verbindings te registreer."</string> <string name="permlab_register_call_provider" msgid="6135073566140050702">"registreer nuwe telekommunikasieverbindings"</string> - <string name="permdesc_register_call_provider" msgid="4201429251459068613">"Laat die program toe om nuwe telekommunikasieverbindings te registreer."</string> + <string name="permdesc_register_call_provider" msgid="4201429251459068613">"Laat die app toe om nuwe telekommunikasieverbindings te registreer."</string> <string name="permlab_connection_manager" msgid="3179365584691166915">"bestuur telekom-verbindings"</string> <string name="permdesc_connection_manager" msgid="1426093604238937733">"Laat die app toe om telekom-verbindings te bestuur."</string> <string name="permlab_bind_incall_service" msgid="5990625112603493016">"beleef interaksie met inoproep-skerm"</string> - <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"Laat die program beheer wanneer en hoe die gebruiker die inoproep-skerm sien."</string> + <string name="permdesc_bind_incall_service" msgid="4124917526967765162">"Laat die app beheer wanneer en hoe die gebruiker die inoproep-skerm sien."</string> <string name="permlab_bind_connection_service" msgid="5409268245525024736">"werk met telefoniedienste saam"</string> - <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"Laat die program toe om met telefoniedienste saam te werk om oproepe te maak of ontvang."</string> + <string name="permdesc_bind_connection_service" msgid="6261796725253264518">"Laat die app toe om met telefoniedienste saam te werk om oproepe te maak of ontvang."</string> <string name="permlab_control_incall_experience" msgid="6436863486094352987">"bied \'n inoproep-gebruikerervaring"</string> - <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"Laat die program toe om \'n inoproep-gebruikerervaring te bied."</string> + <string name="permdesc_control_incall_experience" msgid="5896723643771737534">"Laat die app toe om \'n inoproep-gebruikerervaring te bied."</string> <string name="permlab_readNetworkUsageHistory" msgid="8470402862501573795">"lees netwerkgebruik-geskiedenis"</string> <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"Laat die app toe om historiese netwerkgebruik vir spesifieke netwerke en apps te lees."</string> <string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"bestuur netwerkbeleid"</string> <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Laat die app toe om netwerkbeleide te bestuur en app-spesifieke reëls te definieer."</string> <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"verander verrekening van netwerkgebruik"</string> - <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Laat die program toe om te verander hoe netwerkgebruik teenoor programme gemeet word. Nie vir gebruik deur normale programme nie."</string> + <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Laat die app toe om te verander hoe netwerkgebruik teenoor apps gemeet word. Nie vir gebruik deur normale apps nie."</string> <string name="permlab_accessNotifications" msgid="7130360248191984741">"kry toegang tot kennisgewings"</string> <string name="permdesc_accessNotifications" msgid="761730149268789668">"Laat die program toe om kennisgewings op te haal, te bestudeer en te verwyder, insluitende die kennisgewings wat deur ander programme geplaas is."</string> <string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"bind aan \'n kennisgewingluisteraardiens"</string> @@ -814,11 +814,11 @@ <string name="permlab_setInputCalibration" msgid="932069700285223434">"verander invoertoestelkalibrasie"</string> <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Laat die app toe om die kalibrasieparameters van die raakskerm te wysig. Dit behoort nooit vir normale apps nodig te wees nie."</string> <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"gaan in by DRM-sertifikate"</string> - <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Laat \'n program toe om DRM-sertifikate op te stel en te gebruik. Behoort nooit vir normale programme nodig te wees nie."</string> + <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Laat \'n app toe om DRM-sertifikate op te stel en te gebruik. Dit behoort nooit vir normale apps nodig te wees nie."</string> <string name="permlab_handoverStatus" msgid="7620438488137057281">"ontvang Android Straal-oordragstatus"</string> - <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Laat hierdie program toe om inligting oor huidige Android Straal-oordragte te ontvang."</string> + <string name="permdesc_handoverStatus" msgid="3842269451732571070">"Laat hierdie app toe om inligting oor huidige Android Straal-oordragte te ontvang."</string> <string name="permlab_removeDrmCertificates" msgid="710576248717404416">"verwyder DRM-sertifikate"</string> - <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Laat \'n program toe om DRM-sertifikate te verwyder. Behoort nooit vir gewone programme nodig te wees nie."</string> + <string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"Laat \'n app toe om DRM-sertifikate te verwyder. Dit behoort nooit vir gewone apps nodig te wees nie."</string> <string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"bind aan \'n diensverskaffer-boodskapdiens"</string> <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"Dit laat die houer toe om aan die top-koppelvlak van \'n diensverskaffer-boodskapdiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string> <string name="permlab_bindCarrierServices" msgid="2395596978626237474">"verbind aan diensverskafferdienste"</string> @@ -1106,7 +1106,7 @@ <string name="permlab_setAlarm" msgid="1158001610254173567">"stel \'n wekker"</string> <string name="permdesc_setAlarm" msgid="2185033720060109640">"Laat die app toe om \'n alarm in \'n geïnstalleerde wekkerapp te stel. Sommige wekkerapps werk dalk nie met hierdie funksie nie."</string> <string name="permlab_addVoicemail" msgid="4770245808840814471">"voeg stemboodskap by"</string> - <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Laat die program toe om boodskappe by te voeg by jou stempos-inkassie."</string> + <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Laat die app toe om boodskappe by te voeg by jou stempos-inkassie."</string> <string name="pasted_from_clipboard" msgid="7355790625710831847">"<xliff:g id="PASTING_APP_NAME">%1$s</xliff:g> het van jou knipbord af geplak"</string> <string name="more_item_label" msgid="7419249600215749115">"Meer"</string> <string name="prepend_shortcut_label" msgid="1743716737502867951">"Kieslys+"</string> @@ -1237,7 +1237,7 @@ <string name="low_internal_storage_view_text" msgid="8172166728369697835">"Sommige stelselfunksies werk moontlik nie"</string> <string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"Nie genoeg berging vir die stelsel nie. Maak seker jy het 250 MB spasie beskikbaar en herbegin."</string> <string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> loop tans"</string> - <string name="app_running_notification_text" msgid="5120815883400228566">"Tik vir meer inligting of om die program te stop."</string> + <string name="app_running_notification_text" msgid="5120815883400228566">"Tik vir meer inligting of om die app te stop."</string> <string name="ok" msgid="2646370155170753815">"OK"</string> <string name="cancel" msgid="6908697720451760115">"Kanselleer"</string> <string name="yes" msgid="9069828999585032361">"OK"</string> @@ -1279,7 +1279,7 @@ <string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Vang prent vas met %1$s"</string> <string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Vang prent vas"</string> <string name="alwaysUse" msgid="3153558199076112903">"Gebruik hierdie aksie by verstek."</string> - <string name="use_a_different_app" msgid="4987790276170972776">"Gebruik \'n ander program"</string> + <string name="use_a_different_app" msgid="4987790276170972776">"Gebruik \'n ander app"</string> <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Vee die verstek instelling uit in Stelselinstellings > Programme > Afgelaai."</string> <string name="chooseActivity" msgid="8563390197659779956">"Kies \'n handeling"</string> <string name="chooseUsbActivity" msgid="2096269989990986612">"Kies \'n app vir die USB-toestel"</string> @@ -1303,7 +1303,7 @@ <string name="report" msgid="2149194372340349521">"Verslag"</string> <string name="wait" msgid="7765985809494033348">"Wag"</string> <string name="webpage_unresponsive" msgid="7850879412195273433">"Die bladsy reageer nie meer nie.\n\nWil jy dit toemaak?"</string> - <string name="launch_warning_title" msgid="6725456009564953595">"Program herlei"</string> + <string name="launch_warning_title" msgid="6725456009564953595">"App is herlei"</string> <string name="launch_warning_replace" msgid="3073392976283203402">"<xliff:g id="APP_NAME">%1$s</xliff:g> loop nou."</string> <string name="launch_warning_original" msgid="3332206576800169626">"<xliff:g id="APP_NAME">%1$s</xliff:g> is oorspronklik laat loop."</string> <string name="screen_compat_mode_scale" msgid="8627359598437527726">"Skaal"</string> @@ -1314,7 +1314,7 @@ <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> is gebou vir \'n onversoenbare weergawe van die Android-bedryfstelsel en kan dalk op \'n onverwagte manier reageer. \'n Opgedateerde weergawe van die program is dalk beskikbaar."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Wys altyd"</string> <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Kyk vir opdatering"</string> - <string name="smv_application" msgid="3775183542777792638">"Die program <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) het sy selfopgelegde StrictMode-beleid oortree."</string> + <string name="smv_application" msgid="3775183542777792638">"Die app <xliff:g id="APPLICATION">%1$s</xliff:g> (proses <xliff:g id="PROCESS">%2$s</xliff:g>) het sy selfopgelegde StrictMode-beleid oortree."</string> <string name="smv_process" msgid="1398801497130695446">"Die proses <xliff:g id="PROCESS">%1$s</xliff:g> het die selfopgelegde StrictMode-beleid geskend."</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Foon dateer tans op …"</string> <string name="android_upgrading_title" product="tablet" msgid="4268417249079938805">"Tablet dateer tans oop …"</string> @@ -1397,7 +1397,7 @@ <string name="decline" msgid="6490507610282145874">"Weier"</string> <string name="select_character" msgid="3352797107930786979">"Voeg karakter in"</string> <string name="sms_control_title" msgid="4748684259903148341">"Stuur SMS-boodskappe"</string> - <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> stuur \'n groot aantal SMS-boodskappe. Wil jy hierdie program toelaat om voort te gaan om boodskappe te stuur?"</string> + <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> stuur \'n groot aantal SMS-boodskappe. Wil jy hierdie app toelaat om voort te gaan om boodskappe te stuur?"</string> <string name="sms_control_yes" msgid="4858845109269524622">"Laat toe"</string> <string name="sms_control_no" msgid="4845717880040355570">"Weier"</string> <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> wil \'n boodskap na <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> stuur."</string> @@ -1417,8 +1417,8 @@ <string name="sim_restart_button" msgid="8481803851341190038">"Herbegin"</string> <string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Aktiveer mobiele diens"</string> <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Laai die diensverskafferprogram af om jou nuwe SIM te aktiveer"</string> - <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Laai die <xliff:g id="APP_NAME">%1$s</xliff:g>-program af om jou nuwe SIM te aktiveer"</string> - <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Laai program af"</string> + <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Laai die <xliff:g id="APP_NAME">%1$s</xliff:g>-app af om jou nuwe SIM te aktiveer"</string> + <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Laai app af"</string> <string name="carrier_app_notification_title" msgid="5815477368072060250">"Nuwe SIM is ingesit"</string> <string name="carrier_app_notification_text" msgid="6567057546341958637">"Tik om dit op te stel"</string> <string name="time_picker_dialog_title" msgid="9053376764985220821">"Stel tyd"</string> @@ -1533,13 +1533,13 @@ <string name="permlab_route_media_output" msgid="8048124531439513118">"roeteer media-uitvoer"</string> <string name="permdesc_route_media_output" msgid="1759683269387729675">"Laat \'n app toe om media-uitvoere na ander eksterne toestelle te roeteer."</string> <string name="permlab_readInstallSessions" msgid="7279049337895583621">"lees installeersessies"</string> - <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"Laat \'n program toe om installasiesessies te lees. Dit laat dit toe om besonderhede van aktiewe pakketinstallasies te sien."</string> + <string name="permdesc_readInstallSessions" msgid="4012608316610763473">"Laat \'n app toe om installasiesessies te lees. Dit laat dit toe om besonderhede van aktiewe pakketinstallasies te sien."</string> <string name="permlab_requestInstallPackages" msgid="7600020863445351154">"versoek installeerpakkette"</string> - <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"Laat \'n program toe om te versoek dat pakkette geïnstalleer word."</string> + <string name="permdesc_requestInstallPackages" msgid="3969369278325313067">"Laat \'n app toe om te versoek dat pakkette geïnstalleer word."</string> <string name="permlab_requestDeletePackages" msgid="2541172829260106795">"versoek uitvee van pakkette"</string> - <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Laat \'n program toe om te versoek dat pakkette uitgevee word."</string> + <string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Laat \'n app toe om te versoek dat pakkette uitgevee word."</string> <string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"vra om batteryoptimerings te ignoreer"</string> - <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Laat \'n program toe om toestemming te vra om batteryoptimerings vir daardie program ignoreer."</string> + <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Laat \'n app toe om toestemming te vra om batteryoptimerings vir daardie app te ignoreer."</string> <string name="permlab_queryAllPackages" msgid="2928450604653281650">"navraag oor alle pakkette"</string> <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"Laat \'n program toe om alle geïnstalleerde pakette te sien."</string> <string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Klop twee keer vir zoembeheer"</string> @@ -1561,7 +1561,7 @@ <string name="permission_request_notification_title" msgid="1810025922441048273">"Toestemming versoek"</string> <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Toestemming versoek\nvir rekening <xliff:g id="ACCOUNT">%s</xliff:g>."</string> <string name="permission_request_notification_for_app_with_subtitle" msgid="1298704005732851350">"Toestemming versoek deur <xliff:g id="APP">%1$s</xliff:g>\nvir rekening <xliff:g id="ACCOUNT">%2$s</xliff:g>"</string> - <string name="forward_intent_to_owner" msgid="4620359037192871015">"Jy gebruik hierdie program buite jou werkprofiel"</string> + <string name="forward_intent_to_owner" msgid="4620359037192871015">"Jy gebruik hierdie app buite jou werkprofiel"</string> <string name="forward_intent_to_work" msgid="3620262405636021151">"Jy gebruik tans hierdie app in jou werkprofiel"</string> <string name="input_method_binding_label" msgid="1166731601721983656">"Invoermetode"</string> <string name="sync_binding_label" msgid="469249309424662147">"Sinkroniseer"</string> @@ -2068,9 +2068,9 @@ <string name="app_streaming_blocked_message_for_permission_request" product="tv" msgid="4706276040125072077">"Hierdie app versoek tans bykomende toestemmings, maar toestemmings kan nie in ’n stromingsessie verleen word nie. Verleen eers die toestemming op jou Android TV-toestel."</string> <string name="app_streaming_blocked_message_for_permission_request" product="tablet" msgid="1824604581465771629">"Hierdie app versoek tans bykomende toestemmings, maar toestemmings kan nie in ’n stromingsessie verleen word nie. Verleen eers die toestemming op jou tablet."</string> <string name="app_streaming_blocked_message_for_permission_request" product="default" msgid="7755223160363292105">"Hierdie app versoek tans bykomende toestemmings, maar toestemmings kan nie in ’n stromingsessie verleen word nie. Verleen eers die toestemming op jou foon."</string> - <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Hierdie program versoek tans bykomende sekuriteit. Probeer eerder op jou Android TV-toestel."</string> - <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Hierdie program versoek tans bykomende sekuriteit. Probeer eerder op jou tablet."</string> - <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Hierdie program versoek tans bykomende sekuriteit. Probeer eerder op jou foon."</string> + <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Hierdie app versoek tans bykomende sekuriteit. Probeer eerder op jou Android TV-toestel."</string> + <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Hierdie app versoek tans bykomende sekuriteit. Probeer eerder op jou tablet."</string> + <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Hierdie app versoek tans bykomende sekuriteit. Probeer eerder op jou foon."</string> <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Jy kan nie op jou <xliff:g id="DEVICE">%1$s</xliff:g> toegang hiertoe kry nie. Probeer eerder op jou Android TV-toestel."</string> <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Jy kan nie op jou <xliff:g id="DEVICE">%1$s</xliff:g> toegang hiertoe kry nie. Probeer eerder op jou tablet."</string> <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Jy kan nie op jou <xliff:g id="DEVICE">%1$s</xliff:g> toegang hiertoe kry nie. Probeer eerder op jou foon."</string> @@ -2157,7 +2157,7 @@ <string name="popup_window_default_title" msgid="6907717596694826919">"Opspringvenster"</string> <string name="slice_more_content" msgid="3377367737876888459">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string> <string name="shortcut_restored_on_lower_version" msgid="9206301954024286063">"Programweergawe is afgegradeer, of is nie met hierdie kortpad versoenbaar nie"</string> - <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"Kon nie die kortpad teruglaai nie omdat die program nie rugsteun en teruglaai steun nie"</string> + <string name="shortcut_restore_not_supported" msgid="4763198938588468400">"Kon nie die kortpad teruglaai nie omdat die app nie rugsteun en teruglaai steun nie"</string> <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"Kon nie teruglaai nie omdat programondertekening nie ooreenstem nie"</string> <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"Kon nie kortpad teruglaai nie"</string> <string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"Kortpad is gedeaktiveer"</string> @@ -2403,8 +2403,8 @@ <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> is vertaal."</string> <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"Boodskap is vertaal uit <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> in <xliff:g id="TO_LANGUAGE">%2$s</xliff:g>."</string> <string name="notification_channel_abusive_bg_apps" msgid="6092140213264920355">"Agtergrondaktiwiteit"</string> - <string name="notification_title_abusive_bg_apps" msgid="994230770856147656">"’n Program maak tans die battery pap"</string> - <string name="notification_title_long_running_fgs" msgid="8170284286477131587">"’n Program is nog aktief"</string> + <string name="notification_title_abusive_bg_apps" msgid="994230770856147656">"’n App maak tans die battery pap"</string> + <string name="notification_title_long_running_fgs" msgid="8170284286477131587">"’n App is nog aktief"</string> <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"<xliff:g id="APP">%1$s</xliff:g> loop tans op die agtergrond. Tik om batterygebruik te bestuur."</string> <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> kan batterylewe beïnvloed. Tik om aktiewe programme na te gaan."</string> <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Gaan aktiewe programme na"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index baa54bbf9a8e..a2128088e715 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1158,38 +1158,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"in <xliff:g id="COUNT">%d</xliff:g>h"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"in <xliff:g id="COUNT">%d</xliff:g>d"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"in <xliff:g id="COUNT">%d</xliff:g>y"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"<xliff:g id="COUNT">%d</xliff:g>m ago"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"<xliff:g id="COUNT">%d</xliff:g>h ago"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"<xliff:g id="COUNT">%d</xliff:g>d ago"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"<xliff:g id="COUNT">%d</xliff:g>y ago"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g>hr"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g>d"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g>yr"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"in <xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"in <xliff:g id="COUNT">%d</xliff:g>hr"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"in <xliff:g id="COUNT">%d</xliff:g>d"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"in <xliff:g id="COUNT">%d</xliff:g>yr"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"<xliff:g id="COUNT">%d</xliff:g>min ago"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"<xliff:g id="COUNT">%d</xliff:g>hr ago"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"<xliff:g id="COUNT">%d</xliff:g>d ago"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"<xliff:g id="COUNT">%d</xliff:g>yr ago"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minute ago}other{# minutes ago}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hour ago}other{# hours ago}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# day ago}other{# days ago}}"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 07fa8bffa08f..3d7c91cdbcf2 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1158,38 +1158,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"<xliff:g id="COUNT">%d</xliff:g> 時間後"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"<xliff:g id="COUNT">%d</xliff:g> 日後"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"<xliff:g id="COUNT">%d</xliff:g> 年後"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"<xliff:g id="COUNT">%d</xliff:g> 分前"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"<xliff:g id="COUNT">%d</xliff:g> 時間前"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"<xliff:g id="COUNT">%d</xliff:g> 日前"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"<xliff:g id="COUNT">%d</xliff:g> 年前"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g> 分"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g> 時間"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g> 日"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g> 年"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"あと <xliff:g id="COUNT">%d</xliff:g> 分"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"あと <xliff:g id="COUNT">%d</xliff:g> 時間"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"あと <xliff:g id="COUNT">%d</xliff:g> 日"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"あと <xliff:g id="COUNT">%d</xliff:g> 年"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"<xliff:g id="COUNT">%d</xliff:g> 分前"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"<xliff:g id="COUNT">%d</xliff:g> 時間前"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"<xliff:g id="COUNT">%d</xliff:g> 日前"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"<xliff:g id="COUNT">%d</xliff:g> 年前"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# 分前}other{# 分前}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# 時間前}other{# 時間前}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# 日前}other{# 日前}}"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 384969029f3c..49b4bfc77b42 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -1158,38 +1158,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"<xliff:g id="COUNT">%d</xliff:g> сағ кейін"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"<xliff:g id="COUNT">%d</xliff:g> күннен кейін"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"<xliff:g id="COUNT">%d</xliff:g> жылдан кейін"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"<xliff:g id="COUNT">%d</xliff:g> мин бұрын"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"<xliff:g id="COUNT">%d</xliff:g> сағ бұрын"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"<xliff:g id="COUNT">%d</xliff:g> күн бұрын"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"<xliff:g id="COUNT">%d</xliff:g> жыл бұрын"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g> мин"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g> сағ"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g> күн"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g> жыл"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"<xliff:g id="COUNT">%d</xliff:g> минуттан кейін"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"<xliff:g id="COUNT">%d</xliff:g> сағаттан кейін"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"<xliff:g id="COUNT">%d</xliff:g> күннен кейін"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"<xliff:g id="COUNT">%d</xliff:g> жылдан кейін"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"<xliff:g id="COUNT">%d</xliff:g> мин бұрын"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"<xliff:g id="COUNT">%d</xliff:g> сағ бұрын"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"<xliff:g id="COUNT">%d</xliff:g> күн бұрын"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"<xliff:g id="COUNT">%d</xliff:g> жыл бұрын"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# минут бұрын}other{# минут бұрын}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# сағат бұрын}other{# сағат бұрын}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# күн бұрын}other{# күн бұрын}}"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 85352bc18fdf..ad62f42ef8dc 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -561,13 +561,13 @@ <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"ಟ್ಯಾಬ್ಲೆಟ್ನ ಇನ್ಫ್ರಾರೆಡ್ ಸಂವಾಹಕವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"ನಿಮ್ಮ Android TV ಸಾಧನದ ಇನ್ಫ್ರಾರೆಡ್ ಟ್ರಾನ್ಸ್ಮೀಟರ್ ಅನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"ಫೋನ್ನ ಇನ್ಫ್ರಾರೆಡ್ ಸಂವಾಹಕವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> - <string name="permlab_setWallpaper" msgid="6959514622698794511">"ವಾಲ್ಪೇಪರ್ ಹೊಂದಿಸಿ"</string> + <string name="permlab_setWallpaper" msgid="6959514622698794511">"ವಾಲ್ಪೇಪರ್ ಸೆಟ್ ಮಾಡಿ"</string> <string name="permdesc_setWallpaper" msgid="2973996714129021397">"ಸಿಸ್ಟಂ ವಾಲ್ಪೇಪರ್ ಹೊಂದಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_accessHiddenProfile" msgid="8607094418491556823">"ಮರೆಮಾಡಲಾದ ಪ್ರೊಫೈಲ್ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಿ"</string> <string name="permdesc_accessHiddenProfile" msgid="1543153202481009676">"ಮರೆಮಾಡಲಾದ ಪ್ರೊಫೈಲ್ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_setWallpaperHints" msgid="1153485176642032714">"ನಿಮ್ಮ ವಾಲ್ಪೇಪರ್ ಗಾತ್ರವನ್ನು ಸರಿಹೊಂದಿಸಿ"</string> <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"ಸಿಸ್ಟಂ ವಾಲ್ಪೇಪರ್ ಗಾತ್ರದ ಸುಳಿವುಗಳನ್ನು ಹೊಂದಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> - <string name="permlab_setTimeZone" msgid="7922618798611542432">"ಸಮಯದ ವಲಯವನ್ನು ಹೊಂದಿಸಿ"</string> + <string name="permlab_setTimeZone" msgid="7922618798611542432">"ಸಮಯದ ವಲಯವನ್ನು ಸೆಟ್ ಮಾಡಿ"</string> <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"ಟ್ಯಾಬ್ಲೆಟ್ನ ಸಮಯ ವಲಯವನ್ನು ಬದಲಾಯಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"ನಿಮ್ಮ Android TV ಸಾಧನದ ಸಮಯವಲಯವನ್ನು ಬದಲಾಯಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"ಫೋನ್ನ ಸಮಯ ವಲಯವನ್ನು ಬದಲಾಯಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> @@ -837,7 +837,7 @@ <string name="permdesc_updatePackagesWithoutUserAction" msgid="4567739631260526366">"ಬಳಕೆದಾರರ ಕ್ರಿಯೆಯಿಲ್ಲದೆ ಈ ಹಿಂದೆ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿದ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಹೋಲ್ಡರ್ ಅನ್ನು ಅನುಮತಿಸುತ್ತದೆ"</string> <string name="permlab_writeVerificationStateE2eeContactKeys" msgid="3990742344778360457">"ಇತರ ಆ್ಯಪ್ಗಳ ಮಾಲೀಕತ್ವದ E2EE ಸಂಪರ್ಕ ಕೀಗಳ ಪರಿಶೀಲನೆಯ ಸ್ಥಿತಿಗಳನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಿ"</string> <string name="permdesc_writeVerificationStateE2eeContactKeys" msgid="8453156829747427041">"ಇತರ ಆ್ಯಪ್ಗಳ ಮಾಲೀಕತ್ವದ E2EE ಸಂಪರ್ಕ ಕೀಗಳ ಪರಿಶೀಲನೆಯ ಸ್ಥಿತಿಗಳನ್ನು ಅಪ್ಡೇಟ್ ಮಾಡಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string> - <string name="policylab_limitPassword" msgid="4851829918814422199">"ಪಾಸ್ವರ್ಡ್ ನಿಮಯಗಳನ್ನು ಹೊಂದಿಸಿ"</string> + <string name="policylab_limitPassword" msgid="4851829918814422199">"ಪಾಸ್ವರ್ಡ್ ನಿಮಯಗಳನ್ನು ಸೆಟ್ ಮಾಡಿ"</string> <string name="policydesc_limitPassword" msgid="4105491021115793793">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ನಲ್ಲಿನ ಪಾಸ್ವರ್ಡ್ಗಳು ಮತ್ತು ಪಿನ್ಗಳ ಅನುಮತಿಸಲಾದ ಅಕ್ಷರಗಳ ಪ್ರಮಾಣವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string> <string name="policylab_watchLogin" msgid="7599669460083719504">"ಪರದೆಯ ಅನ್ಲಾಕ್ ಪ್ರಯತ್ನಗಳನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ"</string> <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"ಸ್ಕ್ರೀನ್ ಅನ್ಲಾಕ್ ಮಾಡುವಾಗ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿದ ಪಾಸ್ವರ್ಡ್ಗಳ ಸಂಖ್ಯೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ, ಮತ್ತು ಹಲವಾರು ತಪ್ಪಾದ ಪಾಸ್ವರ್ಡ್ಗಳನ್ನು ಟೈಪ್ ಮಾಡಿದ್ದರೆ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಲಾಕ್ ಮಾಡಿ ಅಥವಾ ಟ್ಯಾಬ್ಲೆಟ್ನ ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕಿ."</string> @@ -863,11 +863,11 @@ <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"ಎಚ್ಚರಿಕೆ ಇಲ್ಲದೆ ಈ Android TV ಸಾಧನದಲ್ಲಿನ ಈ ಬಳಕೆದಾರರ ಡೇಟಾವನ್ನು ಅಳಿಸಿಹಾಕುತ್ತದೆ."</string> <string name="policydesc_wipeData_secondaryUser" product="automotive" msgid="4658832487305780879">"ಎಚ್ಚರಿಕೆಯಿಲ್ಲದೆ ಈ ಇನ್ಫೋಟೈನ್ಮೆಂಟ್ ಸಿಸ್ಟಂನಲ್ಲಿ ಈ ಪ್ರೊಫೈಲ್ನ ಡೇಟಾವನ್ನು ಅಳಿಸಿ."</string> <string name="policydesc_wipeData_secondaryUser" product="default" msgid="2788325512167208654">"ಯಾವುದೇ ಸೂಚನೆ ಇಲ್ಲದೆ ಈ ಫೋನ್ನಲ್ಲಿ ಈ ಬಳಕೆದಾರರ ಡೇಟಾವನ್ನು ಅಳಿಸಿ."</string> - <string name="policylab_setGlobalProxy" msgid="215332221188670221">"ಸಾಧನವನ್ನು ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಗೆ ಹೊಂದಿಸಿ"</string> - <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"ನೀತಿಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ ಬಳಸಬೇಕಾದ ಸಾಧನದ ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಯನ್ನು ಹೊಂದಿಸಿ. ಸಾಧನದ ಮಾಲೀಕರು ಮಾತ್ರ ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಯನ್ನು ಹೊಂದಿಸಬಹುದಾಗಿರುತ್ತದೆ."</string> - <string name="policylab_expirePassword" msgid="6015404400532459169">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಪಾಸ್ವರ್ಡ್ ಮುಕ್ತಾಯವನ್ನು ಹೊಂದಿಸಿ"</string> + <string name="policylab_setGlobalProxy" msgid="215332221188670221">"ಸಾಧನವನ್ನು ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಗೆ ಸೆಟ್ ಮಾಡಿ"</string> + <string name="policydesc_setGlobalProxy" msgid="7149665222705519604">"ನೀತಿಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ ಬಳಸಬೇಕಾದ ಸಾಧನದ ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಯನ್ನು ಸೆಟ್ ಮಾಡಿ. ಸಾಧನದ ಮಾಲೀಕರು ಮಾತ್ರ ಜಾಗತಿಕ ಪ್ರಾಕ್ಸಿಯನ್ನು ಹೊಂದಿಸಬಹುದಾಗಿರುತ್ತದೆ."</string> + <string name="policylab_expirePassword" msgid="6015404400532459169">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಪಾಸ್ವರ್ಡ್ ಮುಕ್ತಾಯವನ್ನು ಸೆಟ್ ಮಾಡಿ"</string> <string name="policydesc_expirePassword" msgid="9136524319325960675">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಪಾಸ್ವರ್ಡ್, ಪಿನ್, ಅಥವಾ ನಮೂನೆಯನ್ನು ಹೆಚ್ಚು ಪದೆ ಪದೇ ಬದಲಾಯಿಸಬೇಕಾಗಿರುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಿ."</string> - <string name="policylab_encryptedStorage" msgid="9012936958126670110">"ಸಂಗ್ರಹಣೆ ಎನ್ಕ್ರಿಪ್ಶನ್ ಹೊಂದಿಸಿ"</string> + <string name="policylab_encryptedStorage" msgid="9012936958126670110">"ಸಂಗ್ರಹಣೆ ಎನ್ಕ್ರಿಪ್ಶನ್ ಸೆಟ್ ಮಾಡಿ"</string> <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"ಸಂಗ್ರಹಿಸಿರುವ ಆ್ಯಪ್ ಡೇಟಾವನ್ನು ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡಬೇಕಾದ ಅಗತ್ಯವಿದೆ."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"ಕ್ಯಾಮರಾಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"ಎಲ್ಲಾ ಸಾಧನ ಕ್ಯಾಮರಾಗಳ ಬಳಕೆಯನ್ನು ತಡೆಯಿರಿ."</string> @@ -1103,7 +1103,7 @@ <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"ಈ ಪುಟದಲ್ಲಿಯೇ ಇರಿ"</string> <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nನೀವು ಈ ಪುಟದಿಂದಾಚೆಗೆ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಲು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?"</string> <string name="autofill_window_title" msgid="4379134104008111961">"<xliff:g id="SERVICENAME">%1$s</xliff:g> ಸಹಾಯದಿಂದ ಸ್ವಯಂ-ಭರ್ತಿ"</string> - <string name="permlab_setAlarm" msgid="1158001610254173567">"ಅಲಾರಮ್ ಹೊಂದಿಸಿ"</string> + <string name="permlab_setAlarm" msgid="1158001610254173567">"ಅಲಾರಮ್ ಸೆಟ್ ಮಾಡಿ"</string> <string name="permdesc_setAlarm" msgid="2185033720060109640">"ಸ್ಥಾಪಿಸಲಾದ ಅಲಾರಮ್ ಗಡಿಯಾರ ಅಪ್ಲಿಕೇಶನ್ನಲ್ಲಿ ಅಲಾರಮ್ ಹೊಂದಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಕೆಲವು ಅಲಾರಮ್ ಗಡಿಯಾರ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸದಿರಬಹುದು."</string> <string name="permlab_addVoicemail" msgid="4770245808840814471">"ಧ್ವನಿಮೇಲ್ ಸೇರಿಸಿ"</string> <string name="permdesc_addVoicemail" msgid="5470312139820074324">"ನಿಮ್ಮ ದ್ವನಿಮೇಲ್ ಇನ್ಬಾಕ್ಸ್ಗೆ ಸಂದೇಶಗಳನ್ನು ಸೇರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> @@ -1158,38 +1158,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"<xliff:g id="COUNT">%d</xliff:g>ಗಂ ಯಲ್ಲಿ"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"<xliff:g id="COUNT">%d</xliff:g>ದಿ ದಲ್ಲಿ"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"<xliff:g id="COUNT">%d</xliff:g>ವ ದಲ್ಲಿ"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"<xliff:g id="COUNT">%d</xliff:g>ನಿಮಿಷದ ಹಿಂದೆ"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"<xliff:g id="COUNT">%d</xliff:g>ಗಂಟೆ ಹಿಂದೆ"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"<xliff:g id="COUNT">%d</xliff:g>ದಿನಗಳ ಹಿಂದೆ"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"<xliff:g id="COUNT">%d</xliff:g>ವರ್ಷದ ಹಿಂದೆ"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g>ನಿಮಿಷ"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g>ಗಂಟೆ"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g>ದಿನ"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g>ವರ್ಷ"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"<xliff:g id="COUNT">%d</xliff:g>ನಿಮಿಷದಲ್ಲಿ"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"<xliff:g id="COUNT">%d</xliff:g>ಗಂಟೆಯಲ್ಲಿ"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"<xliff:g id="COUNT">%d</xliff:g>ದಿನದಲ್ಲಿ"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"<xliff:g id="COUNT">%d</xliff:g>ವರ್ಷದಲ್ಲಿ"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"<xliff:g id="COUNT">%d</xliff:g>ನಿಮಿಷದ ಹಿಂದೆ"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"<xliff:g id="COUNT">%d</xliff:g>ಗಂಟೆ ಹಿಂದೆ"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"<xliff:g id="COUNT">%d</xliff:g>ದಿನಗಳ ಹಿಂದೆ"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"<xliff:g id="COUNT">%d</xliff:g>ವರ್ಷದ ಹಿಂದೆ"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# ನಿಮಿಷದ ಹಿಂದೆ}one{# ನಿಮಿಷಗಳ ಹಿಂದೆ}other{# ನಿಮಿಷಗಳ ಹಿಂದೆ}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# ಗಂಟೆಯ ಹಿಂದೆ}one{# ಗಂಟೆಗಳ ಹಿಂದೆ}other{# ಗಂಟೆಗಳ ಹಿಂದೆ}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# ದಿನದ ಹಿಂದೆ}one{# ದಿನಗಳ ಹಿಂದೆ}other{# ದಿನಗಳ ಹಿಂದೆ}}"</string> @@ -1421,7 +1405,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_picker_dialog_title" msgid="9053376764985220821">"ಸಮಯವನ್ನು ಹೊಂದಿಸಿ"</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> <string name="date_time_done" msgid="8363155889402873463">"ಆಯಿತು"</string> @@ -1622,7 +1606,7 @@ <string name="time_picker_increment_hour_button" msgid="3063572723197178242">"ಗಂಟೆಯನ್ನು ಹೆಚ್ಚಿಸಿ"</string> <string name="time_picker_decrement_hour_button" msgid="584101766855054412">"ಗಂಟೆಯನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string> <string name="time_picker_increment_set_pm_button" msgid="5889149366900376419">"PM ಹೊಂದಿಸು"</string> - <string name="time_picker_decrement_set_am_button" msgid="1422608001541064087">"AM ಹೊಂದಿಸಿ"</string> + <string name="time_picker_decrement_set_am_button" msgid="1422608001541064087">"AM ಸೆಟ್ ಮಾಡಿ"</string> <string name="date_picker_increment_month_button" msgid="3447263316096060309">"ತಿಂಗಳನ್ನು ಹೆಚ್ಚಿಸಿ"</string> <string name="date_picker_decrement_month_button" msgid="6531888937036883014">"ತಿಂಗಳು ಕಡಿಮೆಮಾಡಿ"</string> <string name="date_picker_increment_day_button" msgid="4349336637188534259">"ದಿನವನ್ನು ಹೆಚ್ಚಿಸಿ"</string> @@ -2108,7 +2092,7 @@ <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB ಡೀಬಗ್ ಮಾಡುವಿಕೆ"</string> <string name="time_picker_hour_label" msgid="4208590187662336864">"ಗಂಟೆ"</string> <string name="time_picker_minute_label" msgid="8307452311269824553">"ನಿಮಿಷ"</string> - <string name="time_picker_header_text" msgid="9073802285051516688">"ಸಮಯವನ್ನು ಹೊಂದಿಸಿ"</string> + <string name="time_picker_header_text" msgid="9073802285051516688">"ಸಮಯವನ್ನು ಸೆಟ್ ಮಾಡಿ"</string> <string name="time_picker_input_error" msgid="8386271930742451034">"ಮಾನ್ಯವಾದ ಸಮಯವನ್ನು ನಮೂದಿಸಿ"</string> <string name="time_picker_prompt_label" msgid="303588544656363889">"ಸಮಯ ಟೈಪ್ ಮಾಡಿ"</string> <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"ಸಮಯವನ್ನು ನಮೂದಿಸಲು ಪಠ್ಯದ ನಮೂನೆಗೆ ಬದಲಿಸಿ."</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 1fea24358ad4..21925f8aaab1 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1158,38 +1158,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"dalam <xliff:g id="COUNT">%d</xliff:g>j"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"dalam <xliff:g id="COUNT">%d</xliff:g>h"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"dalam <xliff:g id="COUNT">%d</xliff:g>t"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"<xliff:g id="COUNT">%d</xliff:g>m yang lalu"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"<xliff:g id="COUNT">%d</xliff:g>j yang lalu"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"<xliff:g id="COUNT">%d</xliff:g>h yang lalu"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"<xliff:g id="COUNT">%d</xliff:g>t yang lalu"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g>jam"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g>thn"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"selepas <xliff:g id="COUNT">%d</xliff:g>minit"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"selepas <xliff:g id="COUNT">%d</xliff:g>jam"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"dalam <xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"selepas <xliff:g id="COUNT">%d</xliff:g>thn"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"<xliff:g id="COUNT">%d</xliff:g>minit yang lalu"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"<xliff:g id="COUNT">%d</xliff:g>jam yang lalu"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"<xliff:g id="COUNT">%d</xliff:g>h yang lalu"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"<xliff:g id="COUNT">%d</xliff:g>thn yang lalu"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minit yang lalu}other{# minit yang lalu}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# jam yang lalu}other{# jam yang lalu}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# hari yang lalu}other{# hari yang lalu}}"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 8e943db600d1..5ff383df1770 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1159,38 +1159,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g>h"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> dias"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g>a"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"há <xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"há <xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"há <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"há <xliff:g id="COUNT">%d</xliff:g> a"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g> a"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"em <xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"em <xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"em <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"em <xliff:g id="COUNT">%d</xliff:g> a"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"há <xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"há <xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"há <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"há <xliff:g id="COUNT">%d</xliff:g> a"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}many{# minutos atrás}other{# minutos atrás}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}many{# horas atrás}other{# horas atrás}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}many{# dias atrás}other{# dias atrás}}"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index b5ee46060865..38a071a5cbb2 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1159,38 +1159,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g> h"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> d"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g> a"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"há <xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"há <xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"há <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"há <xliff:g id="COUNT">%d</xliff:g> ano(s)"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g> ano(s)"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"dentro de <xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"dentro de <xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"dentro de <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"dentro de <xliff:g id="COUNT">%d</xliff:g> ano(s)"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"há <xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"há <xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"há <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"há <xliff:g id="COUNT">%d</xliff:g> ano(s)"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Há # minuto}many{Há # minutos}other{Há # minutos}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{há # hora}many{há # horas}other{há # horas}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Há # dia}many{Há # dias}other{Há # dias}}"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 8e943db600d1..5ff383df1770 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1159,38 +1159,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"em <xliff:g id="COUNT">%d</xliff:g>h"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"em <xliff:g id="COUNT">%d</xliff:g> dias"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"em <xliff:g id="COUNT">%d</xliff:g>a"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"há <xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"há <xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"há <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"há <xliff:g id="COUNT">%d</xliff:g> a"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g> a"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"em <xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"em <xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"em <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"em <xliff:g id="COUNT">%d</xliff:g> a"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"há <xliff:g id="COUNT">%d</xliff:g>min"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"há <xliff:g id="COUNT">%d</xliff:g>h"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"há <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"há <xliff:g id="COUNT">%d</xliff:g> a"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# minuto atrás}one{# minuto atrás}many{# minutos atrás}other{# minutos atrás}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# hora atrás}one{# hora atrás}many{# horas atrás}other{# horas atrás}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# dia atrás}one{# dia atrás}many{# dias atrás}other{# dias atrás}}"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index dc61496dfca3..e7e96f50297a 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1160,38 +1160,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"čez <xliff:g id="COUNT">%d</xliff:g> h"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"čez <xliff:g id="COUNT">%d</xliff:g> d"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"čez <xliff:g id="COUNT">%d</xliff:g> l"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"pred <xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"pred <xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"pred <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"pred <xliff:g id="COUNT">%d</xliff:g> l"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g> l"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"čez <xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"čez <xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"čez <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"čez <xliff:g id="COUNT">%d</xliff:g> l"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"pred <xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"pred <xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"pred <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"pred <xliff:g id="COUNT">%d</xliff:g> l"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{Pred # minuto}one{Pred # minuto}two{Pred # minutama}few{Pred # minutami}other{Pred # minutami}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{Pred # uro}one{Pred # uro}two{Pred # urama}few{Pred # urami}other{Pred # urami}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{Pred # dnevom}one{Pred # dnevom}two{Pred # dnevoma}few{Pred # dnevi}other{Pred # dnevi}}"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index a7207ac8156e..4b22b7df0c8c 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1158,38 +1158,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"om <xliff:g id="COUNT">%d</xliff:g> tim"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"om <xliff:g id="COUNT">%d</xliff:g> d"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"om <xliff:g id="COUNT">%d</xliff:g> år"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"för <xliff:g id="COUNT">%d</xliff:g> m sedan"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"för <xliff:g id="COUNT">%d</xliff:g> h sedan"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"för <xliff:g id="COUNT">%d</xliff:g> d sedan"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"för <xliff:g id="COUNT">%d</xliff:g> år sedan"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g> år"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"om <xliff:g id="COUNT">%d</xliff:g> min"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"om <xliff:g id="COUNT">%d</xliff:g> h"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"om <xliff:g id="COUNT">%d</xliff:g> d"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"om <xliff:g id="COUNT">%d</xliff:g> år"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"för <xliff:g id="COUNT">%d</xliff:g> min sedan"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"för <xliff:g id="COUNT">%d</xliff:g> h sedan"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"för <xliff:g id="COUNT">%d</xliff:g> d sedan"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"för <xliff:g id="COUNT">%d</xliff:g> år sedan"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{För # minut sedan}other{För # minuter sedan}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{För # timme sedan}other{För # timmar sedan}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{För # dag sedan}other{För # dagar sedan}}"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 28f06ab64d15..89e2e6859137 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1158,38 +1158,22 @@ <string name="duration_hours_shortest_future" msgid="2979276794547981674">"<xliff:g id="COUNT">%d</xliff:g> soatdan keyin"</string> <string name="duration_days_shortest_future" msgid="3392722163935571543">"<xliff:g id="COUNT">%d</xliff:g> kundan keyin"</string> <string name="duration_years_shortest_future" msgid="5537464088352970388">"<xliff:g id="COUNT">%d</xliff:g> yildan keyin"</string> - <!-- no translation found for duration_minutes_shortest_past (1740022450020492407) --> - <skip /> - <!-- no translation found for duration_hours_shortest_past (2098397414186628489) --> - <skip /> - <!-- no translation found for duration_days_shortest_past (1832006037955897625) --> - <skip /> - <!-- no translation found for duration_years_shortest_past (6168256514200469291) --> - <skip /> - <!-- no translation found for duration_minutes_medium (5891933490342643944) --> - <skip /> - <!-- no translation found for duration_hours_medium (1465359726485910115) --> - <skip /> - <!-- no translation found for duration_days_medium (5994225628248661388) --> - <skip /> - <!-- no translation found for duration_years_medium (734023884353592526) --> - <skip /> - <!-- no translation found for duration_minutes_medium_future (2750894988731934402) --> - <skip /> - <!-- no translation found for duration_hours_medium_future (6050833881463849764) --> - <skip /> - <!-- no translation found for duration_days_medium_future (1700821545602729963) --> - <skip /> - <!-- no translation found for duration_years_medium_future (3281018940397120166) --> - <skip /> - <!-- no translation found for duration_minutes_medium_past (7400424340181947714) --> - <skip /> - <!-- no translation found for duration_hours_medium_past (6709441336035202617) --> - <skip /> - <!-- no translation found for duration_days_medium_past (5748156261134344532) --> - <skip /> - <!-- no translation found for duration_years_medium_past (893797065424596243) --> - <skip /> + <string name="duration_minutes_shortest_past" msgid="1740022450020492407">"<xliff:g id="COUNT">%d</xliff:g> daq oldin"</string> + <string name="duration_hours_shortest_past" msgid="2098397414186628489">"<xliff:g id="COUNT">%d</xliff:g> soat oldin"</string> + <string name="duration_days_shortest_past" msgid="1832006037955897625">"<xliff:g id="COUNT">%d</xliff:g> kun oldin"</string> + <string name="duration_years_shortest_past" msgid="6168256514200469291">"<xliff:g id="COUNT">%d</xliff:g> yil oldin"</string> + <string name="duration_minutes_medium" msgid="5891933490342643944">"<xliff:g id="COUNT">%d</xliff:g>daq"</string> + <string name="duration_hours_medium" msgid="1465359726485910115">"<xliff:g id="COUNT">%d</xliff:g>st"</string> + <string name="duration_days_medium" msgid="5994225628248661388">"<xliff:g id="COUNT">%d</xliff:g> k"</string> + <string name="duration_years_medium" msgid="734023884353592526">"<xliff:g id="COUNT">%d</xliff:g>yil"</string> + <string name="duration_minutes_medium_future" msgid="2750894988731934402">"<xliff:g id="COUNT">%d</xliff:g> daqiqadan keyin"</string> + <string name="duration_hours_medium_future" msgid="6050833881463849764">"<xliff:g id="COUNT">%d</xliff:g> soatdan keyin"</string> + <string name="duration_days_medium_future" msgid="1700821545602729963">"<xliff:g id="COUNT">%d</xliff:g> kundan keyin"</string> + <string name="duration_years_medium_future" msgid="3281018940397120166">"<xliff:g id="COUNT">%d</xliff:g> yildan keyin"</string> + <string name="duration_minutes_medium_past" msgid="7400424340181947714">"<xliff:g id="COUNT">%d</xliff:g> daqiqa oldin"</string> + <string name="duration_hours_medium_past" msgid="6709441336035202617">"<xliff:g id="COUNT">%d</xliff:g> soat oldin"</string> + <string name="duration_days_medium_past" msgid="5748156261134344532">"<xliff:g id="COUNT">%d</xliff:g> kun oldin"</string> + <string name="duration_years_medium_past" msgid="893797065424596243">"<xliff:g id="COUNT">%d</xliff:g> yil oldin"</string> <string name="duration_minutes_relative" msgid="8620337701051015593">"{count,plural, =1{# daqiqa oldin}other{# daqiqa oldin}}"</string> <string name="duration_hours_relative" msgid="4836449961693180253">"{count,plural, =1{# soat oldin}other{# soat oldin}}"</string> <string name="duration_days_relative" msgid="621965767567258302">"{count,plural, =1{# kun oldin}other{# kun oldin}}"</string> diff --git a/core/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml index e735784ee5bb..17860ef6d9f2 100644 --- a/core/res/res/xml/bookmarks.xml +++ b/core/res/res/xml/bookmarks.xml @@ -20,14 +20,10 @@ Typical shortcuts (not necessarily defined here): 'b': Browser - 'c': Contacts + 'p': Contacts 'e': Email - 'g': GMail - 'k': Calendar + 'c': Calendar 'm': Maps - 'p': Music - 's': SMS - 't': Talk 'u': Calculator 'y': YouTube --> @@ -38,7 +34,7 @@ androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CONTACTS" - androidprv:keycode="KEYCODE_C" + androidprv:keycode="KEYCODE_P" androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_EMAIL" @@ -46,21 +42,13 @@ androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALENDAR" - androidprv:keycode="KEYCODE_K" + androidprv:keycode="KEYCODE_C" androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MAPS" androidprv:keycode="KEYCODE_M" androidprv:modifierState="META" /> <bookmark - category="android.intent.category.APP_MUSIC" - androidprv:keycode="KEYCODE_P" - androidprv:modifierState="META" /> - <bookmark - role="android.app.role.SMS" - androidprv:keycode="KEYCODE_S" - androidprv:modifierState="META" /> - <bookmark category="android.intent.category.APP_CALCULATOR" androidprv:keycode="KEYCODE_U" androidprv:modifierState="META" /> diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt index 18e4fde280ec..4a227d8ff1ef 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt +++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt @@ -318,11 +318,11 @@ class DisplayTopologyTest { verifyDisplay(actualDisplay2, id = 2, width = 200f, height = 600f, POSITION_RIGHT, offset = 0f, noOfChildren = 2) - val actualDisplay3 = actualDisplay2.children[1] + val actualDisplay3 = actualDisplay2.children[0] verifyDisplay(actualDisplay3, id = 3, width = 600f, height = 200f, POSITION_RIGHT, offset = 10f, noOfChildren = 0) - val actualDisplay4 = actualDisplay2.children[0] + val actualDisplay4 = actualDisplay2.children[1] verifyDisplay(actualDisplay4, id = 4, width = 200f, height = 600f, POSITION_RIGHT, offset = 210f, noOfChildren = 0) } @@ -402,42 +402,46 @@ class DisplayTopologyTest { @Test fun rearrange_twoDisplays() { - val nodes = rearrangeRects( + val root = rearrangeRects( // Arrange in staggered manner, connected vertically. RectF(100f, 100f, 250f, 200f), RectF(150f, 200f, 300f, 300f), ) - assertThat(nodes[0].children).containsExactly(nodes[1]) - assertThat(nodes[1].children).isEmpty() - assertPositioning(nodes, Pair(POSITION_BOTTOM, 50f)) + verifyDisplay(root, id = 0, width = 150f, height = 100f, noOfChildren = 1) + val node = root.children[0] + verifyDisplay( + node, id = 1, width = 150f, height = 100f, POSITION_BOTTOM, offset = 50f, + noOfChildren = 0) } @Test fun rearrange_reverseOrderOfSeveralDisplays() { - val nodes = rearrangeRects( + val root = rearrangeRects( RectF(0f, 0f, 150f, 100f), RectF(-150f, 0f, 0f, 100f), RectF(-300f, 0f, -150f, 100f), RectF(-450f, 0f, -300f, 100f), ) - assertPositioning( - nodes, - Pair(POSITION_LEFT, 0f), - Pair(POSITION_LEFT, 0f), - Pair(POSITION_LEFT, 0f), - ) - - assertThat(nodes[0].children).containsExactly(nodes[1]) - assertThat(nodes[1].children).containsExactly(nodes[2]) - assertThat(nodes[2].children).containsExactly(nodes[3]) - assertThat(nodes[3].children).isEmpty() + verifyDisplay(root, id = 0, width = 150f, height = 100f, noOfChildren = 1) + var node = root.children[0] + verifyDisplay( + node, id = 1, width = 150f, height = 100f, POSITION_LEFT, offset = 0f, + noOfChildren = 1) + node = node.children[0] + verifyDisplay( + node, id = 2, width = 150f, height = 100f, POSITION_LEFT, offset = 0f, + noOfChildren = 1) + node = node.children[0] + verifyDisplay( + node, id = 3, width = 150f, height = 100f, POSITION_LEFT, offset = 0f, + noOfChildren = 0) } @Test fun rearrange_crossWithRootInCenter() { - val nodes = rearrangeRects( + val root = rearrangeRects( RectF(0f, 0f, 150f, 100f), RectF(-150f, 0f, 0f, 100f), RectF(0f, -100f, 150f, 0f), @@ -445,21 +449,24 @@ class DisplayTopologyTest { RectF(0f, 100f, 150f, 200f), ) - assertPositioning( - nodes, - Pair(POSITION_LEFT, 0f), - Pair(POSITION_TOP, 0f), - Pair(POSITION_RIGHT, 0f), - Pair(POSITION_BOTTOM, 0f), - ) - - assertThat(nodes[0].children) - .containsExactly(nodes[1], nodes[2], nodes[3], nodes[4]) + verifyDisplay(root, id = 0, width = 150f, height = 100f, noOfChildren = 4) + verifyDisplay( + root.children[0], id = 1, width = 150f, height = 100f, POSITION_LEFT, offset = 0f, + noOfChildren = 0) + verifyDisplay( + root.children[1], id = 2, width = 150f, height = 100f, POSITION_TOP, offset = 0f, + noOfChildren = 0) + verifyDisplay( + root.children[2], id = 3, width = 150f, height = 100f, POSITION_RIGHT, offset = 0f, + noOfChildren = 0) + verifyDisplay( + root.children[3], id = 4, width = 150f, height = 100f, POSITION_BOTTOM, offset = 0f, + noOfChildren = 0) } @Test fun rearrange_elbowArrangementDoesNotUseCornerAdjacency1() { - val nodes = rearrangeRects( + val root = rearrangeRects( // 2 // | // 0 - 1 @@ -469,20 +476,20 @@ class DisplayTopologyTest { RectF(100f, -100f, 200f, 0f), ) - assertThat(nodes[0].children).containsExactly(nodes[1]) - assertThat(nodes[1].children).containsExactly(nodes[2]) - assertThat(nodes[2].children).isEmpty() - - assertPositioning( - nodes, - Pair(POSITION_RIGHT, 0f), - Pair(POSITION_TOP, 0f), - ) + verifyDisplay(root, id = 0, width = 100f, height = 100f, noOfChildren = 1) + var node = root.children[0] + verifyDisplay( + node, id = 1, width = 100f, height = 100f, POSITION_RIGHT, offset = 0f, + noOfChildren = 1) + node = node.children[0] + verifyDisplay( + node, id = 2, width = 100f, height = 100f, POSITION_TOP, + offset = 0f, noOfChildren = 0) } @Test fun rearrange_elbowArrangementDoesNotUseCornerAdjacency2() { - val nodes = rearrangeRects( + val root = rearrangeRects( // 0 // | // 1 @@ -495,22 +502,24 @@ class DisplayTopologyTest { RectF(-100f, 200f, 0f, 300f), ) - assertThat(nodes[0].children).containsExactly(nodes[1]) - assertThat(nodes[1].children).containsExactly(nodes[2]) - assertThat(nodes[2].children).containsExactly(nodes[3]) - assertThat(nodes[3].children).isEmpty() - - assertPositioning( - nodes, - Pair(POSITION_BOTTOM, 0f), - Pair(POSITION_BOTTOM, 0f), - Pair(POSITION_LEFT, 0f), - ) + verifyDisplay(root, id = 0, width = 100f, height = 100f, noOfChildren = 1) + var node = root.children[0] + verifyDisplay( + node, id = 1, width = 100f, height = 100f, POSITION_BOTTOM, offset = 0f, + noOfChildren = 1) + node = node.children[0] + verifyDisplay( + node, id = 2, width = 100f, height = 100f, POSITION_BOTTOM, offset = 0f, + noOfChildren = 1) + node = node.children[0] + verifyDisplay( + node, id = 3, width = 100f, height = 100f, POSITION_LEFT, offset = 0f, + noOfChildren = 0) } @Test fun rearrange_useLargerEdge() { - val nodes = rearrangeRects( + val root = rearrangeRects( // 444111 // 444111 // 444111 @@ -527,23 +536,24 @@ class DisplayTopologyTest { RectF(0f, 0f, 30f, 30f), ) - assertPositioning( - nodes, - Pair(POSITION_TOP, 10f), - Pair(POSITION_RIGHT, 0f), - Pair(POSITION_BOTTOM, -10f), - Pair(POSITION_LEFT, 0f), - ) - - assertThat(nodes[0].children).containsExactly(nodes[1], nodes[2]) - assertThat(nodes[1].children).containsExactly(nodes[4]) - assertThat(nodes[2].children).containsExactly(nodes[3]) - (3..4).forEach { assertThat(nodes[it].children).isEmpty() } + verifyDisplay(root, id = 0, width = 30f, height = 30f, noOfChildren = 2) + verifyDisplay( + root.children[0], id = 1, width = 30f, height = 30f, POSITION_TOP, + offset = 10f, noOfChildren = 1) + verifyDisplay( + root.children[0].children[0], id = 4, width = 30f, height = 30f, POSITION_LEFT, + offset = 0f, noOfChildren = 0) + verifyDisplay( + root.children[1], id = 2, width = 30f, height = 30f, POSITION_RIGHT, + offset = 0f, noOfChildren = 1) + verifyDisplay( + root.children[1].children[0], id = 3, width = 30f, height = 30f, POSITION_BOTTOM, + offset = -10f, noOfChildren = 0) } @Test fun rearrange_closeGaps() { - val nodes = rearrangeRects( + val root = rearrangeRects( // 000 // 000 111 // 000 111 @@ -558,16 +568,14 @@ class DisplayTopologyTest { // TOP/BOTTOM attach ) - assertPositioning( - nodes, - // In the case of corner adjacency, we prefer a left/right attachment. - Pair(POSITION_RIGHT, 10f), - Pair(POSITION_BOTTOM, 30f), - ) - - assertThat(nodes[0].children).containsExactly(nodes[1]) - assertThat(nodes[1].children).containsExactly(nodes[2]) - assertThat(nodes[2].children).isEmpty() + verifyDisplay(root, id = 0, width = 30f, height = 30f, noOfChildren = 1) + verifyDisplay( + root.children[0], id = 1, width = 30f, height = 30f, POSITION_RIGHT, offset = 10f, + noOfChildren = 1) + // In the case of corner adjacency, we prefer a left/right attachment. + verifyDisplay( + root.children[0].children[0], id = 2, width = 29.5f, height = 30f, POSITION_BOTTOM, + offset = 30f, noOfChildren = 0) } @Test @@ -612,8 +620,10 @@ class DisplayTopologyTest { /** * Runs the rearrange algorithm and returns the resulting tree as a list of nodes, with the * root at index 0. The number of nodes is inferred from the number of positions passed. + * + * Returns the root node. */ - private fun rearrangeRects(vararg pos: RectF): List<DisplayTopology.TreeNode> { + private fun rearrangeRects(vararg pos: RectF): DisplayTopology.TreeNode { // Generates a linear sequence of nodes in order in the List from root to leaf, // left-to-right. IDs are ascending from 0 to count - 1. @@ -631,7 +641,7 @@ class DisplayTopologyTest { PointF(pos[it].left, pos[it].top) }) - return nodes + return nodes[0] } private fun verifyDisplay(display: DisplayTopology.TreeNode, id: Int, width: Float, @@ -644,11 +654,4 @@ class DisplayTopologyTest { assertThat(display.offset).isEqualTo(offset) assertThat(display.children).hasSize(noOfChildren) } - - private fun assertPositioning( - nodes: List<DisplayTopology.TreeNode>, vararg positions: Pair<Int, Float>) { - assertThat(nodes.drop(1).map { Pair(it.position, it.offset) }) - .containsExactly(*positions) - .inOrder() - } } diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java index 402b92a3f2a2..26806b143629 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java @@ -16,16 +16,23 @@ package android.view.textclassifier; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.mock; +import android.Manifest; import android.content.Context; +import android.permission.flags.Flags; +import android.platform.test.annotations.RequiresFlagsEnabled; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -61,4 +68,28 @@ public class TextClassificationManagerTest { assertThat(mTcm.getTextClassifier(TextClassifier.SYSTEM)) .isInstanceOf(SystemTextClassifier.class); } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_TEXT_CLASSIFIER_CHOICE_API_ENABLED) + public void testGetClassifier() { + Assume.assumeTrue(Flags.textClassifierChoiceApiEnabled()); + assertThrows(SecurityException.class, + () -> mTcm.getClassifier(TextClassifier.CLASSIFIER_TYPE_DEVICE_DEFAULT)); + assertThrows(SecurityException.class, + () -> mTcm.getClassifier(TextClassifier.CLASSIFIER_TYPE_ANDROID_DEFAULT)); + assertThrows(SecurityException.class, + () -> mTcm.getClassifier(TextClassifier.CLASSIFIER_TYPE_SELF_PROVIDED)); + + runWithShellPermissionIdentity(() -> { + assertThat( + mTcm.getClassifier(TextClassifier.CLASSIFIER_TYPE_DEVICE_DEFAULT)).isInstanceOf( + SystemTextClassifier.class); + assertThat(mTcm.getClassifier( + TextClassifier.CLASSIFIER_TYPE_ANDROID_DEFAULT)).isInstanceOf( + SystemTextClassifier.class); + assertThat(mTcm.getClassifier( + TextClassifier.CLASSIFIER_TYPE_SELF_PROVIDED)).isSameInstanceAs( + TextClassifier.NO_OP); + }, Manifest.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE); + } } diff --git a/core/tests/coretests/src/android/window/WindowContextTest.java b/core/tests/coretests/src/android/window/WindowContextTest.java index 21930d17ed68..b9344261cade 100644 --- a/core/tests/coretests/src/android/window/WindowContextTest.java +++ b/core/tests/coretests/src/android/window/WindowContextTest.java @@ -33,7 +33,9 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.Activity; import android.app.EmptyActivity; @@ -48,7 +50,9 @@ import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.Binder; import android.os.IBinder; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; import android.view.Display; import android.view.IWindowManager; import android.view.View; @@ -64,6 +68,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.rule.ActivityTestRule; import com.android.frameworks.coretests.R; +import com.android.window.flags.Flags; import org.junit.After; import org.junit.Before; @@ -91,6 +96,8 @@ public class WindowContextTest { public ActivityTestRule<EmptyActivity> mActivityRule = new ActivityTestRule<>(EmptyActivity.class, false /* initialTouchMode */, false /* launchActivity */); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); private final WindowContext mWindowContext = createWindowContext(); @@ -340,17 +347,35 @@ public class WindowContextTest { } @Test - public void updateDisplay_wasAttached_detachThenAttachedPropagatedToTokenController() { + @EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void reparentToDisplayId_wasAttached_reparentToDisplayAreaPropagatedToTokenController() { + final WindowTokenClientController mockWindowTokenClientController = + mock(WindowTokenClientController.class); + when(mockWindowTokenClientController.attachToDisplayArea(any(), anyInt(), anyInt(), + any())).thenReturn(true); + WindowTokenClientController.overrideForTesting(mockWindowTokenClientController); + + mWindowContext.reparentToDisplay(DEFAULT_DISPLAY + 1); + + verify(mockWindowTokenClientController).reparentToDisplayArea(any(), + /* displayId= */ eq(DEFAULT_DISPLAY + 1) + ); + } + + @Test + @EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void reparentToDisplayId_sameDisplayId_noReparenting() { final WindowTokenClientController mockWindowTokenClientController = mock(WindowTokenClientController.class); + when(mockWindowTokenClientController.attachToDisplayArea(any(), anyInt(), anyInt(), + any())).thenReturn(true); WindowTokenClientController.overrideForTesting(mockWindowTokenClientController); - mWindowContext.updateDisplay(DEFAULT_DISPLAY + 1); + mWindowContext.reparentToDisplay(DEFAULT_DISPLAY); - verify(mockWindowTokenClientController).detachIfNeeded(any()); - verify(mockWindowTokenClientController).attachToDisplayArea(any(), - anyInt(), /* displayId= */ eq(DEFAULT_DISPLAY + 1), - any()); + verify(mockWindowTokenClientController, never()).reparentToDisplayArea(any(), + /* displayId= */ eq(DEFAULT_DISPLAY) + ); } private WindowContext createWindowContext() { diff --git a/core/tests/coretests/src/com/android/internal/view/ScrollCaptureInternalTest.java b/core/tests/coretests/src/com/android/internal/view/ScrollCaptureInternalTest.java new file mode 100644 index 000000000000..5f6d806bc064 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/view/ScrollCaptureInternalTest.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.view; + +import static android.view.flags.Flags.FLAG_SCROLL_CAPTURE_RELAX_SCROLL_VIEW_CRITERIA; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.internal.view.ScrollCaptureInternal.TYPE_FIXED; +import static com.android.internal.view.ScrollCaptureInternal.TYPE_OPAQUE; +import static com.android.internal.view.ScrollCaptureInternal.TYPE_RECYCLING; +import static com.android.internal.view.ScrollCaptureInternal.TYPE_SCROLLING; +import static com.android.internal.view.ScrollCaptureInternal.detectScrollingType; + +import static org.junit.Assert.assertEquals; + +import android.content.Context; +import android.graphics.Rect; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; +import android.testing.AndroidTestingRunner; +import android.view.ViewGroup; + +import androidx.test.filters.SmallTest; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests scrolling detection. + */ +@Presubmit +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class ScrollCaptureInternalTest { + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + /** + * Tests the effect of padding on scroll capture search dispatch. + * <p> + * Verifies computation of child visible bounds with padding. + */ + @Test + public void testDetectScrollingType_scrolling_notScrollable() { + MockScrollable scrollable = new MockScrollable.Builder() + .bounds(0, 0, 200, 200) + .childCount(1) + .canScrollUp(false) + .canScrollDown(false) + .scrollToEnabled(false) + .build(getInstrumentation().getContext()); + + assertEquals(TYPE_FIXED, detectScrollingType(scrollable)); + } + + @Test + public void testDetectScrollingType_scrolling_noChildren() { + MockScrollable scrollable = new MockScrollable.Builder() + .bounds(0, 0, 200, 200) + .childCount(0) + .canScrollUp(false) + .canScrollDown(true) + .scrollToEnabled(true) + .build(getInstrumentation().getContext()); + + assertEquals(TYPE_OPAQUE, detectScrollingType(scrollable)); + } + + @Test + public void testDetectScrollingType_scrolling() { + MockScrollable scrollable = new MockScrollable.Builder() + .bounds(0, 0, 200, 200) + .childCount(1) + .canScrollUp(false) + .canScrollDown(true) + .scrollToEnabled(true) + .build(getInstrumentation().getContext()); + + assertEquals(TYPE_SCROLLING, detectScrollingType(scrollable)); + } + + @Test + public void testDetectScrollingType_scrolling_partiallyScrolled() { + MockScrollable scrollable = new MockScrollable.Builder() + .bounds(0, 0, 200, 200) + .childCount(1) + .canScrollUp(true) + .canScrollDown(true) + .scrollToEnabled(true) + .build(getInstrumentation().getContext()); + scrollable.scrollTo(0, 100); + + assertEquals(TYPE_SCROLLING, detectScrollingType(scrollable)); + } + + @Test + @EnableFlags(FLAG_SCROLL_CAPTURE_RELAX_SCROLL_VIEW_CRITERIA) + public void testDetectScrollingType_scrolling_multipleChildren() { + MockScrollable scrollable = new MockScrollable.Builder() + .bounds(0, 0, 200, 200) + .childCount(10) + .canScrollUp(false) + .canScrollDown(true) + .scrollToEnabled(true) + .build(getInstrumentation().getContext()); + + assertEquals(TYPE_SCROLLING, detectScrollingType(scrollable)); + } + + @Test + public void testDetectScrollingType_recycling() { + MockScrollable scrollable = new MockScrollable.Builder() + .bounds(0, 0, 200, 200) + .childCount(10) + .canScrollUp(false) + .canScrollDown(true) + .scrollToEnabled(false) + .build(getInstrumentation().getContext()); + + assertEquals(TYPE_RECYCLING, detectScrollingType(scrollable)); + } + + @Test + public void testDetectScrollingType_noChildren() { + MockScrollable scrollable = new MockScrollable.Builder() + .bounds(0, 0, 200, 200) + .childCount(0) + .canScrollUp(true) + .canScrollDown(true) + .scrollToEnabled(false) + .build(getInstrumentation().getContext()); + + assertEquals(TYPE_OPAQUE, detectScrollingType(scrollable)); + } + + + /** + * A mock which can exhibit some attributes and behaviors used to detect different types + * of scrolling content. + */ + private static class MockScrollable extends ViewGroup { + private final int mChildCount; + private final boolean mCanScrollUp; + private final boolean mCanScrollDown; + private final boolean mScrollToEnabled; + + MockScrollable(Context context, Rect bounds, int childCount, boolean canScrollUp, + boolean canScrollDown, boolean scrollToEnabled) { + super(context); + setFrame(bounds.left, bounds.top, bounds.right, bounds.bottom); + mCanScrollUp = canScrollUp; + mCanScrollDown = canScrollDown; + mScrollToEnabled = scrollToEnabled; + mChildCount = childCount; + } + + private static class Builder { + private int mChildCount; + private boolean mCanScrollUp; + private boolean mCanScrollDown; + private boolean mScrollToEnabled = true; + + private final Rect mBounds = new Rect(); + + public MockScrollable build(Context context) { + return new MockScrollable(context, + mBounds, mChildCount, mCanScrollUp, mCanScrollDown, + mScrollToEnabled); + } + + public Builder canScrollUp(boolean canScrollUp) { + mCanScrollUp = canScrollUp; + return this; + } + + public Builder canScrollDown(boolean canScrollDown) { + mCanScrollDown = canScrollDown; + return this; + } + + public Builder scrollToEnabled(boolean enabled) { + mScrollToEnabled = enabled; + return this; + } + + public Builder childCount(int childCount) { + mChildCount = childCount; + return this; + } + + public Builder bounds(int left, int top, int right, int bottom) { + mBounds.set(left, top, right, bottom); + return this; + } + } + + @Override + public boolean canScrollVertically(int direction) { + if (direction > 0) { + return mCanScrollDown; + } else if (direction < 0) { + return mCanScrollUp; + } else { + return false; + } + } + + @Override + public int getChildCount() { + return mChildCount; + } + + @Override + public void scrollTo(int x, int y) { + if (mScrollToEnabled) { + super.scrollTo(x, y); + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + // We don't layout this view. + } + } +} diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 9bf4d65e1865..2e885145819c 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -34,6 +34,7 @@ import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; +import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.graphics.text.TextRunShaper; import android.os.Build; @@ -2141,6 +2142,14 @@ public class Paint { * @see FontVariationAxis */ public boolean setFontVariationSettings(String fontVariationSettings) { + return setFontVariationSettings(fontVariationSettings, 0 /* wght adjust */); + } + + /** + * Set font variation settings with weight adjustment + * @hide + */ + public boolean setFontVariationSettings(String fontVariationSettings, int wghtAdjust) { final boolean useFontVariationStore = Flags.typefaceRedesignReadonly() && CompatChanges.isChangeEnabled(NEW_FONT_VARIATION_MANAGEMENT); if (useFontVariationStore) { @@ -2154,8 +2163,13 @@ public class Paint { long builderPtr = nCreateFontVariationBuilder(axes.length); for (int i = 0; i < axes.length; ++i) { - nAddFontVariationToBuilder(builderPtr, axes[i].getOpenTypeTagValue(), - axes[i].getStyleValue()); + int tag = axes[i].getOpenTypeTagValue(); + float value = axes[i].getStyleValue(); + if (tag == 0x77676874 /* wght */) { + value = Math.clamp(value + wghtAdjust, + FontStyle.FONT_WEIGHT_MIN, FontStyle.FONT_WEIGHT_MAX); + } + nAddFontVariationToBuilder(builderPtr, tag, value); } nSetFontVariationOverride(mNativePaint, builderPtr); mFontVariationSettings = fontVariationSettings; diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt index b38d00da6dfa..1d0c5057c77f 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt @@ -602,8 +602,72 @@ class BubblePositionerTest { testGetBubbleBarExpandedViewBounds(onLeft = false, isOverflow = true) } + @Test + fun getExpandedViewContainerPadding_largeScreen_fitsMaxViewWidth() { + val expandedViewWidth = context.resources.getDimensionPixelSize( + R.dimen.bubble_expanded_view_largescreen_width + ) + // set the screen size so that it is wide enough to fit the maximum width size + val screenWidth = expandedViewWidth * 2 + positioner.update( + defaultDeviceConfig.copy( + windowBounds = Rect(0, 0, screenWidth, 2000), + isLargeScreen = true, + isLandscape = false + ) + ) + val paddings = + positioner.getExpandedViewContainerPadding(/* onLeft= */ true, /* isOverflow= */ false) + + val padding = context.resources.getDimensionPixelSize( + R.dimen.bubble_expanded_view_largescreen_landscape_padding + ) + val right = screenWidth - expandedViewWidth - padding + assertThat(paddings).isEqualTo(intArrayOf(padding - positioner.pointerSize, 0, right, 0)) + } + + @Test + fun getExpandedViewContainerPadding_largeScreen_doesNotFitMaxViewWidth() { + positioner.update( + defaultDeviceConfig.copy( + windowBounds = Rect(0, 0, 600, 2000), + isLargeScreen = true, + isLandscape = false + ) + ) + val paddings = + positioner.getExpandedViewContainerPadding(/* onLeft= */ true, /* isOverflow= */ false) + + val padding = context.resources.getDimensionPixelSize( + R.dimen.bubble_expanded_view_largescreen_landscape_padding + ) + // the screen is not wide enough to fit the maximum width size, so the view fills the screen + // minus left and right padding + assertThat(paddings).isEqualTo(intArrayOf(padding - positioner.pointerSize, 0, padding, 0)) + } + + @Test + fun getExpandedViewContainerPadding_smallTablet() { + val screenWidth = 500 + positioner.update( + defaultDeviceConfig.copy( + windowBounds = Rect(0, 0, screenWidth, 2000), + isLargeScreen = true, + isSmallTablet = true, + isLandscape = false + ) + ) + val paddings = + positioner.getExpandedViewContainerPadding(/* onLeft= */ true, /* isOverflow= */ false) + + // for small tablets, the view width is set to be 0.72 * screen width + val viewWidth = (screenWidth * 0.72).toInt() + val padding = (screenWidth - viewWidth) / 2 + assertThat(paddings).isEqualTo(intArrayOf(padding - positioner.pointerSize, 0, padding, 0)) + } + private fun testGetBubbleBarExpandedViewBounds(onLeft: Boolean, isOverflow: Boolean) { - positioner.setShowingInBubbleBar(true) + positioner.isShowingInBubbleBar = true val windowBounds = Rect(0, 0, 2000, 2600) val insets = Insets.of(10, 20, 5, 15) val deviceConfig = diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt new file mode 100644 index 000000000000..0d8f80935f5a --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.bubbles.bar + +import android.content.Context +import android.graphics.Insets +import android.graphics.Rect +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.FrameLayout +import androidx.core.animation.AnimatorTestRule +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import com.android.internal.logging.testing.UiEventLoggerFake +import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.bubbles.Bubble +import com.android.wm.shell.bubbles.BubbleExpandedViewManager +import com.android.wm.shell.bubbles.BubbleLogger +import com.android.wm.shell.bubbles.BubbleOverflow +import com.android.wm.shell.bubbles.BubblePositioner +import com.android.wm.shell.bubbles.DeviceConfig +import com.android.wm.shell.bubbles.FakeBubbleExpandedViewManager +import com.android.wm.shell.bubbles.FakeBubbleFactory +import com.android.wm.shell.bubbles.FakeBubbleTaskViewFactory +import com.google.common.truth.Truth.assertThat +import java.util.concurrent.Semaphore +import java.util.concurrent.TimeUnit +import org.junit.After +import org.junit.Before +import org.junit.ClassRule +import org.junit.Test +import org.junit.runner.RunWith + +/** Tests for [BubbleBarAnimationHelper] */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class BubbleBarAnimationHelperTest { + + companion object { + @JvmField @ClassRule val animatorTestRule: AnimatorTestRule = AnimatorTestRule() + + const val SCREEN_WIDTH = 2000 + const val SCREEN_HEIGHT = 1000 + } + + private val context = ApplicationProvider.getApplicationContext<Context>() + + private lateinit var animationHelper: BubbleBarAnimationHelper + private lateinit var bubblePositioner: BubblePositioner + private lateinit var expandedViewManager: BubbleExpandedViewManager + private lateinit var bubbleLogger: BubbleLogger + private lateinit var mainExecutor: TestShellExecutor + private lateinit var bgExecutor: TestShellExecutor + private lateinit var container: FrameLayout + + @Before + fun setUp() { + ProtoLog.REQUIRE_PROTOLOGTOOL = false + ProtoLog.init() + val windowManager = context.getSystemService(WindowManager::class.java) + bubblePositioner = BubblePositioner(context, windowManager) + bubblePositioner.setShowingInBubbleBar(true) + val deviceConfig = + DeviceConfig( + windowBounds = Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), + isLargeScreen = true, + isSmallTablet = false, + isLandscape = true, + isRtl = false, + insets = Insets.of(10, 20, 30, 40), + ) + bubblePositioner.update(deviceConfig) + expandedViewManager = FakeBubbleExpandedViewManager() + bubbleLogger = BubbleLogger(UiEventLoggerFake()) + + mainExecutor = TestShellExecutor() + bgExecutor = TestShellExecutor() + + container = FrameLayout(context) + + animationHelper = BubbleBarAnimationHelper(context, bubblePositioner) + } + + @After + fun tearDown() { + bgExecutor.flushAll() + mainExecutor.flushAll() + } + + @Test + fun animateSwitch_bubbleToBubble_oldHiddenNewShown() { + val fromBubble = createBubble(key = "from").initialize(container) + val toBubble = createBubble(key = "to").initialize(container) + + val semaphore = Semaphore(0) + val after = Runnable { semaphore.release() } + + getInstrumentation().runOnMainSync { + animationHelper.animateSwitch(fromBubble, toBubble, after) + animatorTestRule.advanceTimeBy(1000) + } + getInstrumentation().waitForIdleSync() + + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(fromBubble.bubbleBarExpandedView?.visibility).isEqualTo(View.INVISIBLE) + assertThat(fromBubble.bubbleBarExpandedView?.alpha).isEqualTo(0f) + assertThat(fromBubble.bubbleBarExpandedView?.isSurfaceZOrderedOnTop).isFalse() + + assertThat(toBubble.bubbleBarExpandedView?.visibility).isEqualTo(View.VISIBLE) + assertThat(toBubble.bubbleBarExpandedView?.alpha).isEqualTo(1f) + assertThat(toBubble.bubbleBarExpandedView?.isSurfaceZOrderedOnTop).isFalse() + } + + @Test + fun animateSwitch_bubbleToBubble_handleColorTransferred() { + val fromBubble = createBubble(key = "from").initialize(container) + fromBubble.bubbleBarExpandedView!! + .handleView + .updateHandleColor(/* isRegionDark= */ true, /* animated= */ false) + val toBubble = createBubble(key = "to").initialize(container) + + getInstrumentation().runOnMainSync { + animationHelper.animateSwitch(fromBubble, toBubble, /* afterAnimation= */ null) + animatorTestRule.advanceTimeBy(1000) + } + getInstrumentation().waitForIdleSync() + + assertThat(toBubble.bubbleBarExpandedView!!.handleView.handleColor) + .isEqualTo(fromBubble.bubbleBarExpandedView!!.handleView.handleColor) + } + + @Test + fun animateSwitch_bubbleToOverflow_oldHiddenNewShown() { + val fromBubble = createBubble(key = "from").initialize(container) + val overflow = createOverflow().initialize(container) + + val semaphore = Semaphore(0) + val after = Runnable { semaphore.release() } + + getInstrumentation().runOnMainSync { + animationHelper.animateSwitch(fromBubble, overflow, after) + animatorTestRule.advanceTimeBy(1000) + } + getInstrumentation().waitForIdleSync() + + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(fromBubble.bubbleBarExpandedView?.visibility).isEqualTo(View.INVISIBLE) + assertThat(fromBubble.bubbleBarExpandedView?.alpha).isEqualTo(0f) + assertThat(fromBubble.bubbleBarExpandedView?.isSurfaceZOrderedOnTop).isFalse() + + assertThat(overflow.bubbleBarExpandedView?.visibility).isEqualTo(View.VISIBLE) + assertThat(overflow.bubbleBarExpandedView?.alpha).isEqualTo(1f) + } + + @Test + fun animateSwitch_overflowToBubble_oldHiddenNewShown() { + val overflow = createOverflow().initialize(container) + val toBubble = createBubble(key = "to").initialize(container) + + val semaphore = Semaphore(0) + val after = Runnable { semaphore.release() } + + getInstrumentation().runOnMainSync { + animationHelper.animateSwitch(overflow, toBubble, after) + animatorTestRule.advanceTimeBy(1000) + } + getInstrumentation().waitForIdleSync() + + assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue() + assertThat(overflow.bubbleBarExpandedView?.visibility).isEqualTo(View.INVISIBLE) + assertThat(overflow.bubbleBarExpandedView?.alpha).isEqualTo(0f) + + assertThat(toBubble.bubbleBarExpandedView?.visibility).isEqualTo(View.VISIBLE) + assertThat(toBubble.bubbleBarExpandedView?.alpha).isEqualTo(1f) + assertThat(toBubble.bubbleBarExpandedView?.isSurfaceZOrderedOnTop).isFalse() + } + + private fun createBubble(key: String): Bubble { + val bubbleBarExpandedView = + FakeBubbleFactory.createExpandedView( + context, + bubblePositioner, + expandedViewManager, + FakeBubbleTaskViewFactory(context, mainExecutor).create(), + mainExecutor, + bgExecutor, + bubbleLogger, + ) + val viewInfo = FakeBubbleFactory.createViewInfo(bubbleBarExpandedView) + return FakeBubbleFactory.createChatBubble(context, key, viewInfo) + } + + private fun createOverflow(): BubbleOverflow { + val overflow = BubbleOverflow(context, bubblePositioner) + overflow.initializeForBubbleBar(expandedViewManager, bubblePositioner, bubbleLogger) + return overflow + } + + private fun Bubble.initialize(container: ViewGroup): Bubble { + getInstrumentation().runOnMainSync { container.addView(bubbleBarExpandedView) } + // Mark taskView's visible + bubbleBarExpandedView!!.onContentVisibilityChanged(true) + return this + } + + private fun BubbleOverflow.initialize(container: ViewGroup): BubbleOverflow { + getInstrumentation().runOnMainSync { container.addView(bubbleBarExpandedView) } + return this + } +} diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java index 04c17e54d11f..4c77eaf80a29 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java @@ -91,6 +91,9 @@ public class DesktopModeStatus { /** The maximum override density allowed for tasks inside the desktop. */ private static final int DESKTOP_DENSITY_MAX = 1000; + /** The number of [WindowDecorViewHost] instances to warm up on system start. */ + private static final int WINDOW_DECOR_PRE_WARM_SIZE = 2; + /** * Sysprop declaring whether to enters desktop mode by default when the windowing mode of the * display's root TaskDisplayArea is set to WINDOWING_MODE_FREEFORM. @@ -122,6 +125,14 @@ public class DesktopModeStatus { private static final String MAX_TASK_LIMIT_SYS_PROP = "persist.wm.debug.desktop_max_task_limit"; /** + * Sysprop declaring the number of [WindowDecorViewHost] instances to warm up on system start. + * + * <p>If it is not defined, then [WINDOW_DECOR_PRE_WARM_SIZE] is used. + */ + private static final String WINDOW_DECOR_PRE_WARM_SIZE_SYS_PROP = + "persist.wm.debug.desktop_window_decor_pre_warm_size"; + + /** * Return {@code true} if veiled resizing is active. If false, fluid resizing is used. */ public static boolean isVeiledResizeEnabled() { @@ -162,6 +173,27 @@ public class DesktopModeStatus { } /** + * Return the maximum size of the window decoration surface control view host pool, or zero if + * there should be no pooling. + */ + public static int getWindowDecorScvhPoolSize(@NonNull Context context) { + if (!Flags.enableDesktopWindowingScvhCacheBugFix()) return 0; + final int maxTaskLimit = getMaxTaskLimit(context); + if (maxTaskLimit > 0) { + return maxTaskLimit; + } + // TODO: b/368032552 - task limit equal to 0 means unlimited. Figure out what the pool + // size should be in that case. + return 0; + } + + /** The number of [WindowDecorViewHost] instances to warm up on system start. */ + public static int getWindowDecorPreWarmSize() { + return SystemProperties.getInt(WINDOW_DECOR_PRE_WARM_SIZE_SYS_PROP, + WINDOW_DECOR_PRE_WARM_SIZE); + } + + /** * Return {@code true} if the current device supports desktop mode. */ @VisibleForTesting diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 673d8b36439c..60a52a808a54 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -214,6 +214,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } ProtoLog.i(WM_SHELL_BACK_PREVIEW, "Navigation window gone."); setTriggerBack(false); + // Trigger close transition if necessary. + if (Flags.migratePredictiveBackTransition()) { + mBackTransitionHandler.onAnimationFinished(); + } resetTouchTracker(); // Don't wait for animation start mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable); 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 0fd4206c0545..de85d9af127d 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 @@ -163,8 +163,11 @@ public class BubblePositioner { mExpandedViewLargeScreenWidth = (int) (bounds.width() * EXPANDED_VIEW_SMALL_TABLET_WIDTH_PERCENT); } else { - mExpandedViewLargeScreenWidth = - res.getDimensionPixelSize(R.dimen.bubble_expanded_view_largescreen_width); + int expandedViewLargeScreenSpacing = res.getDimensionPixelSize( + R.dimen.bubble_expanded_view_largescreen_landscape_padding); + mExpandedViewLargeScreenWidth = Math.min( + res.getDimensionPixelSize(R.dimen.bubble_expanded_view_largescreen_width), + bounds.width() - expandedViewLargeScreenSpacing * 2); } if (mDeviceConfig.isLargeScreen()) { if (mDeviceConfig.isSmallTablet()) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java index 4d7c7fad53f8..3e8a9b64dac6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java @@ -272,6 +272,7 @@ public class BubbleBarAnimationHelper { final float startTx = getSwitchAnimationInitialTx(endTx); toBbev.setTranslationX(startTx); toBbev.getHandleView().setAlpha(0f); + toBbev.getHandleView().setHandleInitialColor(fromBbev.getHandleView().getHandleColor()); toBbev.animateExpansionWhenTaskViewVisible(() -> { AnimatorSet switchAnim = new AnimatorSet(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java index 2c0483c50710..65c929ab6fb4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java @@ -606,6 +606,11 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView mTaskView.setZOrderedOnTop(onTop, true /* allowDynamicChange */); } + @VisibleForTesting + boolean isSurfaceZOrderedOnTop() { + return mTaskView != null && mTaskView.isZOrderedOnTop(); + } + /** * Sets whether the view is animating, in this case we won't change the content visibility * until the animation is done. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java index 712e41b0b3c5..9cf0d2db710b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleView.java @@ -65,6 +65,7 @@ public class BubbleBarHandleView extends View { @Nullable private ObjectAnimator mColorChangeAnim; private @ColorInt int mRegionSamplerColor; + private boolean mHasSampledColor; public BubbleBarHandleView(Context context) { this(context, null /* attrs */); @@ -102,7 +103,11 @@ public class BubbleBarHandleView extends View { invalidate(); } - private int getHandleColor() { + /** + * Get current color value for the handle + */ + @ColorInt + public int getHandleColor() { return mHandlePaint.getColor(); } @@ -128,6 +133,16 @@ public class BubbleBarHandleView extends View { } /** + * Set initial color for the handle. Takes effect if the + * {@link #updateHandleColor(boolean, boolean)} has not been called. + */ + public void setHandleInitialColor(@ColorInt int color) { + if (!mHasSampledColor) { + setHandleColor(color); + } + } + + /** * Updates the handle color. * * @param isRegionDark Whether the background behind the handle is dark, and thus the handle @@ -139,6 +154,7 @@ public class BubbleBarHandleView extends View { if (newColor == mRegionSamplerColor) { return; } + mHasSampledColor = true; mRegionSamplerColor = newColor; if (mColorChangeAnim != null) { mColorChangeAnim.cancel(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt index ef964f40dab3..8e149ac2869a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt @@ -66,3 +66,41 @@ infix fun LetterboxController.append(other: LetterboxController) = object : Lett other.dump() } } + +object LetterboxUtils { + // Utility methods about Maps usage in Letterbox. + object Maps { + /* + * Executes [onFound] on the [item] for a given [key] if present or + * [onMissed] if the [key] is not present. + */ + fun <V, K> MutableMap<K, V>.runOnItem( + key: K, + onFound: (V) -> Unit = { _ -> }, + onMissed: ( + K, + MutableMap<K, V> + ) -> Unit = { _, _ -> } + ) { + this[key]?.let { + return onFound(it) + } + return onMissed(key, this) + } + } + + // Utility methods about Transaction usage in Letterbox. + object Transactions { + // Sets position and crops in one method. + fun Transaction.moveAndCrop( + surface: SurfaceControl, + rect: Rect + ): Transaction = + setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) + .setWindowCrop( + surface, + rect.width(), + rect.height() + ) + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt index 5129d03b9dbc..6861aa3763b5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt @@ -20,6 +20,8 @@ import android.graphics.Rect import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import com.android.wm.shell.dagger.WMSingleton import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT import javax.inject.Inject @@ -101,23 +103,6 @@ class MultiSurfaceLetterboxController @Inject constructor( ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}") } - /* - * Executes [onFound] on the [LetterboxItem] if present or [onMissed] if not present. - */ - private fun MutableMap<LetterboxKey, LetterboxSurfaces>.runOnItem( - key: LetterboxKey, - onFound: (LetterboxSurfaces) -> Unit = { _ -> }, - onMissed: ( - LetterboxKey, - MutableMap<LetterboxKey, LetterboxSurfaces> - ) -> Unit = { _, _ -> } - ) { - this[key]?.let { - return onFound(it) - } - return onMissed(key, this) - } - private fun SurfaceControl?.remove( tx: Transaction ) = this?.let { @@ -131,17 +116,6 @@ class MultiSurfaceLetterboxController @Inject constructor( tx.setVisibility(this, visible) } - private fun Transaction.moveAndCrop( - surface: SurfaceControl, - rect: Rect - ): Transaction = - setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) - .setWindowCrop( - surface, - rect.width(), - rect.height() - ) - private fun LetterboxSurfaces.updateSurfacesBounds( tx: Transaction, taskBounds: Rect, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt index a67f6082c892..8e1cdee0c862 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt @@ -20,6 +20,8 @@ import android.graphics.Rect import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import com.android.wm.shell.dagger.WMSingleton import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT import javax.inject.Inject @@ -106,32 +108,4 @@ class SingleSurfaceLetterboxController @Inject constructor( override fun dump() { ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}") } - - /* - * Executes [onFound] on the [SurfaceControl] if present or [onMissed] if not present. - */ - private fun MutableMap<LetterboxKey, SurfaceControl>.runOnItem( - key: LetterboxKey, - onFound: (SurfaceControl) -> Unit = { _ -> }, - onMissed: ( - LetterboxKey, - MutableMap<LetterboxKey, SurfaceControl> - ) -> Unit = { _, _ -> } - ) { - this[key]?.let { - return onFound(it) - } - return onMissed(key, this) - } - - private fun Transaction.moveAndCrop( - surface: SurfaceControl, - rect: Rect - ): Transaction = - setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) - .setWindowCrop( - surface, - rect.width(), - rect.height() - ) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 86e0d08ba05a..0cd0f4a97bbf 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 @@ -152,6 +152,7 @@ import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel; import com.android.wm.shell.windowdecor.WindowDecorViewModel; import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer; import com.android.wm.shell.windowdecor.common.viewhost.DefaultWindowDecorViewHostSupplier; +import com.android.wm.shell.windowdecor.common.viewhost.PooledWindowDecorViewHostSupplier; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost; import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier; import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationPromoController; @@ -347,7 +348,15 @@ public abstract class WMShellModule { @WMSingleton @Provides static WindowDecorViewHostSupplier<WindowDecorViewHost> provideWindowDecorViewHostSupplier( - @ShellMainThread @NonNull CoroutineScope mainScope) { + @NonNull Context context, + @ShellMainThread @NonNull CoroutineScope mainScope, + @NonNull ShellInit shellInit) { + final int poolSize = DesktopModeStatus.getWindowDecorScvhPoolSize(context); + final int preWarmSize = DesktopModeStatus.getWindowDecorPreWarmSize(); + if (DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context) && poolSize > 0) { + return new PooledWindowDecorViewHostSupplier( + context, mainScope, shellInit, poolSize, preWarmSize); + } return new DefaultWindowDecorViewHostSupplier(mainScope); } 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 1a484042cf26..0bc7ca982ec2 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 @@ -363,8 +363,15 @@ class DesktopTasksController( } val tdaInfo = rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId) - requireNotNull(tdaInfo) { - "This method can only be called with the ID of a display having non-null DisplayArea." + // A non-organized display (e.g., non-trusted virtual displays used in CTS) doesn't have + // TDA. + if (tdaInfo == null) { + logW( + "forceEnterDesktop cannot find DisplayAreaInfo for displayId=%d. This could happen" + + " when the display is a non-trusted virtual display.", + displayId, + ) + return false } val tdaWindowingMode = tdaInfo.configuration.windowConfiguration.windowingMode val isFreeformDisplay = tdaWindowingMode == WINDOWING_MODE_FREEFORM @@ -906,7 +913,10 @@ class DesktopTasksController( destinationBounds.height(), displayController, ) - toggleResizeDesktopTaskTransitionHandler.startTransition(wct) + toggleResizeDesktopTaskTransitionHandler.startTransition( + wct, + interaction.animationStartBounds, + ) } private fun dragToMaximizeDesktopTask( @@ -937,6 +947,7 @@ class DesktopTasksController( direction = ToggleTaskSizeInteraction.Direction.MAXIMIZE, source = ToggleTaskSizeInteraction.Source.HEADER_DRAG_TO_TOP, inputMethod = DesktopModeEventLogger.getInputMethodFromMotionEvent(motionEvent), + animationStartBounds = currentDragBounds, ), ) } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/common/ToggleTaskSizeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/common/ToggleTaskSizeUtils.kt index 7afd8d7f6e48..f6ebf7221e82 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/common/ToggleTaskSizeUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/common/ToggleTaskSizeUtils.kt @@ -15,6 +15,7 @@ */ package com.android.wm.shell.desktopmode.common +import android.graphics.Rect import com.android.internal.jank.Cuj import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.InputMethod import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger @@ -23,10 +24,13 @@ import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction.Ambiguo import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction.Source /** Represents a user interaction to toggle a desktop task's size from to maximize or vice versa. */ -data class ToggleTaskSizeInteraction( +data class ToggleTaskSizeInteraction +@JvmOverloads +constructor( val direction: Direction, val source: Source, val inputMethod: InputMethod, + val animationStartBounds: Rect? = null, ) { constructor( isMaximized: Boolean, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index a368245db25f..2998a076a56c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -512,6 +512,11 @@ public class SplitScreenController implements SplitDragPolicy.Starter, mStageCoordinator.getStageBounds(outTopOrLeftBounds, outBottomOrRightBounds); } + /** Get the parent-based coordinates for split stages. */ + public void getRefStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) { + mStageCoordinator.getRefStageBounds(outTopOrLeftBounds, outBottomOrRightBounds); + } + public void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) { mStageCoordinator.registerSplitScreenListener(listener); } 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 b40996f52bd3..5eadd060ca44 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 @@ -1776,6 +1776,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, outBottomOrRightBounds.set(mSplitLayout.getBottomRightBounds()); } + void getRefStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) { + outTopOrLeftBounds.set(mSplitLayout.getTopLeftRefBounds()); + outBottomOrRightBounds.set(mSplitLayout.getBottomRightRefBounds()); + } + private void runForActiveStages(Consumer<StageTaskListener> consumer) { mStageOrderOperator.getActiveStages().forEach(consumer); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java index 82c0aaf3bc8b..361d766370e5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskView.java @@ -186,6 +186,7 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, */ public void setObscuredTouchRect(Rect obscuredRect) { mObscuredTouchRegion = obscuredRect != null ? new Region(obscuredRect) : null; + invalidate(); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt index 4d95cde1492f..01fc6440712d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopHandleManageWindowsMenu.kt @@ -19,19 +19,18 @@ package com.android.wm.shell.windowdecor import android.app.ActivityManager.RunningTaskInfo import android.content.Context import android.graphics.Point -import android.graphics.Rect +import android.view.View import android.view.WindowManager import android.window.TaskSnapshot import androidx.compose.ui.graphics.toArgb +import com.android.wm.shell.R import com.android.wm.shell.shared.desktopmode.DesktopModeStatus import com.android.wm.shell.shared.multiinstance.ManageWindowsViewContainer -import com.android.wm.shell.shared.split.SplitScreenConstants import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer +import com.android.wm.shell.windowdecor.common.calculateMenuPosition import com.android.wm.shell.windowdecor.common.DecorThemeUtil -import com.android.wm.shell.windowdecor.extension.isFullscreen -import com.android.wm.shell.windowdecor.extension.isMultiWindow /** * Implementation of [ManageWindowsViewContainer] meant to be used in desktop header and app @@ -59,35 +58,19 @@ class DesktopHandleManageWindowsMenu( } private fun calculateMenuPosition(): Point { - val position = Point() - val nonFreeformX = (captionX + (captionWidth / 2) - (menuView.menuWidth / 2)) - when { - callerTaskInfo.isFreeform -> { - val taskBounds = callerTaskInfo.getConfiguration().windowConfiguration.bounds - position.set(taskBounds.left, taskBounds.top) - } - callerTaskInfo.isFullscreen -> { - position.set(nonFreeformX, 0) - } - callerTaskInfo.isMultiWindow -> { - val splitPosition = splitScreenController.getSplitPosition(callerTaskInfo.taskId) - val leftOrTopStageBounds = Rect() - val rightOrBottomStageBounds = Rect() - splitScreenController.getStageBounds(leftOrTopStageBounds, rightOrBottomStageBounds) - // TODO(b/343561161): This needs to be calculated differently if the task is in - // top/bottom split. - when (splitPosition) { - SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT -> { - position.set(leftOrTopStageBounds.width() + nonFreeformX, /* y= */ 0) - } - - SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT -> { - position.set(nonFreeformX, /* y= */ 0) - } - } - } - } - return position + return calculateMenuPosition( + splitScreenController, + callerTaskInfo, + marginStart = 0, + marginTop = context.resources.getDimensionPixelSize( + R.dimen.desktop_mode_handle_menu_margin_top + ), + captionX, + 0, + captionWidth, + menuView.menuWidth, + context.isRtl() + ) } override fun addToContainer(menuView: ManageWindowsView) { @@ -109,4 +92,7 @@ class DesktopHandleManageWindowsMenu( override fun removeFromContainer() { menuViewContainer?.releaseView() } + + private fun Context.isRtl() = + resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index 049b8d621427..1179b0cd226c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -47,12 +47,12 @@ import androidx.compose.ui.graphics.toArgb import androidx.core.view.isGone import com.android.window.flags.Flags import com.android.wm.shell.R -import com.android.wm.shell.apptoweb.isBrowserApp import com.android.wm.shell.shared.split.SplitScreenConstants import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer import com.android.wm.shell.windowdecor.common.DecorThemeUtil +import com.android.wm.shell.windowdecor.common.calculateMenuPosition import com.android.wm.shell.windowdecor.extension.isFullscreen import com.android.wm.shell.windowdecor.extension.isMultiWindow import com.android.wm.shell.windowdecor.extension.isPinned @@ -240,7 +240,19 @@ class HandleMenu( val menuX: Int val menuY: Int val taskBounds = taskInfo.getConfiguration().windowConfiguration.bounds - updateGlobalMenuPosition(taskBounds, captionX, captionY) + globalMenuPosition.set( + calculateMenuPosition( + splitScreenController, + taskInfo, + marginStart = marginMenuStart, + marginMenuTop, + captionX, + captionY, + captionWidth, + menuWidth, + context.isRtl() + ) + ) if (layoutResId == R.layout.desktop_mode_app_header) { // Align the handle menu to the start of the header. menuX = if (context.isRtl()) { @@ -265,53 +277,6 @@ class HandleMenu( handleMenuPosition.set(menuX.toFloat(), menuY.toFloat()) } - private fun updateGlobalMenuPosition(taskBounds: Rect, captionX: Int, captionY: Int) { - val nonFreeformX = captionX + (captionWidth / 2) - (menuWidth / 2) - when { - taskInfo.isFreeform -> { - if (context.isRtl()) { - globalMenuPosition.set( - /* x= */ taskBounds.right - menuWidth - marginMenuStart, - /* y= */ taskBounds.top + captionY + marginMenuTop - ) - } else { - globalMenuPosition.set( - /* x= */ taskBounds.left + marginMenuStart, - /* y= */ taskBounds.top + captionY + marginMenuTop - ) - } - } - taskInfo.isFullscreen -> { - globalMenuPosition.set( - /* x = */ nonFreeformX, - /* y = */ marginMenuTop + captionY - ) - } - taskInfo.isMultiWindow -> { - val splitPosition = splitScreenController.getSplitPosition(taskInfo.taskId) - val leftOrTopStageBounds = Rect() - val rightOrBottomStageBounds = Rect() - splitScreenController.getStageBounds(leftOrTopStageBounds, rightOrBottomStageBounds) - // TODO(b/343561161): This needs to be calculated differently if the task is in - // top/bottom split. - when (splitPosition) { - SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT -> { - globalMenuPosition.set( - /* x = */ leftOrTopStageBounds.width() + nonFreeformX, - /* y = */ captionY + marginMenuTop - ) - } - SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT -> { - globalMenuPosition.set( - /* x = */ nonFreeformX, - /* y = */ captionY + marginMenuTop - ) - } - } - } - } - } - /** * Update pill layout, in case task changes have caused positioning to change. */ @@ -374,8 +339,6 @@ class HandleMenu( ) if (splitScreenController.getSplitPosition(taskInfo.taskId) == SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT) { - // TODO(b/343561161): This also needs to be calculated differently if - // the task is in top/bottom split. val leftStageBounds = Rect() splitScreenController.getStageBounds(leftStageBounds, Rect()) inputRelativeToMenu.x += leftStageBounds.width().toFloat() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/DesktopMenuPositionUtility.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/DesktopMenuPositionUtility.kt new file mode 100644 index 000000000000..6def3daf8c8d --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/DesktopMenuPositionUtility.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.windowdecor.common + +import android.app.ActivityManager.RunningTaskInfo +import android.graphics.Point +import android.graphics.Rect +import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT +import com.android.wm.shell.splitscreen.SplitScreenController +import com.android.wm.shell.windowdecor.extension.isFullscreen + +/** Utility function used for calculating position of desktop mode menus. */ +fun calculateMenuPosition( + splitScreenController: SplitScreenController, + taskInfo: RunningTaskInfo, + marginStart: Int, + marginTop: Int, + captionX: Int, + captionY: Int, + captionWidth: Int, + menuWidth: Int, + isRtl: Boolean, +): Point { + if (taskInfo.isFreeform) { + val taskBounds = taskInfo.configuration.windowConfiguration.bounds + return if (isRtl) { + Point( + /* x= */ taskBounds.right - menuWidth - marginStart, + /* y= */ taskBounds.top + marginTop, + ) + } else { + Point(/* x= */ taskBounds.left + marginStart, /* y= */ taskBounds.top + marginTop) + } + } + val nonFreeformPosition = Point(captionX + (captionWidth / 2) - (menuWidth / 2), captionY) + if (taskInfo.isFullscreen) { + return Point(nonFreeformPosition.x, nonFreeformPosition.y + marginTop) + } + // Only the splitscreen case left. + val splitPosition = splitScreenController.getSplitPosition(taskInfo.taskId) + val leftOrTopStageBounds = Rect() + val rightOrBottomStageBounds = Rect() + splitScreenController.getRefStageBounds(leftOrTopStageBounds, rightOrBottomStageBounds) + if (splitScreenController.isLeftRightSplit) { + val rightStageModifier = + if (splitPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT) { + rightOrBottomStageBounds.left + } else { + 0 + } + return Point( + /* x = */ rightStageModifier + nonFreeformPosition.x, + /* y = */ nonFreeformPosition.y + marginTop, + ) + } else { + val bottomSplitModifier = + if (splitPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT) { + rightOrBottomStageBounds.top + } else { + 0 + } + return Point( + /* x = */ nonFreeformPosition.x, + /* y = */ nonFreeformPosition.y + bottomSplitModifier + marginTop, + ) + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/PooledWindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/PooledWindowDecorViewHostSupplier.kt new file mode 100644 index 000000000000..47cfaeed6157 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/PooledWindowDecorViewHostSupplier.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.windowdecor.common.viewhost + +import android.content.Context +import android.os.Trace +import android.util.Pools +import android.view.Display +import android.view.SurfaceControl +import com.android.wm.shell.shared.annotations.ShellMainThread +import com.android.wm.shell.sysui.ShellInit +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +/** + * A [WindowDecorViewHostSupplier] backed by a pool to allow recycling view hosts which may be + * expensive to recreate for each new or updated window decoration. + * + * Callers can obtain a [WindowDecorViewHost] using [acquire], which will return a pooled object if + * available, or create a new instance and return it if needed. When finished using a + * [WindowDecorViewHost], it must be released using [release] to allow it to be sent back into the + * pool and reused later on. + * + * This class also supports pre-warming [ReusableWindowDecorViewHost] instances, which will be put + * into the pool immediately after creation. + */ +class PooledWindowDecorViewHostSupplier( + private val context: Context, + @ShellMainThread private val mainScope: CoroutineScope, + shellInit: ShellInit, + maxPoolSize: Int, + private val preWarmSize: Int, +) : WindowDecorViewHostSupplier<WindowDecorViewHost> { + + private val pool: Pools.Pool<WindowDecorViewHost> = Pools.SynchronizedPool(maxPoolSize) + private var nextDecorViewHostId = 0 + + init { + require(preWarmSize <= maxPoolSize) { "Pre-warm size should not exceed pool size" } + shellInit.addInitCallback(this::onShellInit, this) + } + + private fun onShellInit() { + if (preWarmSize <= 0) { + return + } + preWarmViewHosts(preWarmSize) + } + + private fun preWarmViewHosts(preWarmSize: Int) { + mainScope.launch { + // Applying isn't needed, as the surface was never actually shown. + val t = SurfaceControl.Transaction() + repeat(preWarmSize) { + val warmedViewHost = newInstance(context, context.display).apply { warmUp() } + // Put the warmed view host in the pool by releasing it. + release(warmedViewHost, t) + } + } + } + + override fun acquire(context: Context, display: Display): WindowDecorViewHost { + val pooledViewHost = pool.acquire() + if (pooledViewHost != null) { + return pooledViewHost + } + Trace.beginSection("PooledWindowDecorViewHostSupplier#acquire-newInstance") + val newDecorViewHost = newInstance(context, display) + Trace.endSection() + return newDecorViewHost + } + + override fun release(viewHost: WindowDecorViewHost, t: SurfaceControl.Transaction) { + val pooled = pool.release(viewHost) + if (!pooled) { + viewHost.release(t) + } + } + + private fun newInstance(context: Context, display: Display): ReusableWindowDecorViewHost { + // Use a reusable window decor view host, as it allows swapping the entire view hierarchy. + return ReusableWindowDecorViewHost( + context = context, + mainScope = mainScope, + display = display, + id = nextDecorViewHostId++, + ) + } +} 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 new file mode 100644 index 000000000000..da41e1b1d8d8 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHost.kt @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.common.viewhost + +import android.content.Context +import android.content.res.Configuration +import android.graphics.PixelFormat +import android.graphics.Region +import android.view.Display +import android.view.SurfaceControl +import android.view.View +import android.view.WindowManager +import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE +import android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH +import android.view.WindowManager.LayoutParams.TYPE_APPLICATION +import android.widget.FrameLayout +import androidx.tracing.Trace +import com.android.internal.annotations.VisibleForTesting +import com.android.wm.shell.shared.annotations.ShellMainThread +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch + +/** + * An implementation of [WindowDecorViewHost] that supports: + * 1) Replacing the root [View], meaning [WindowDecorViewHost.updateView] maybe be called with + * different [View] instances. This is useful when reusing [WindowDecorViewHost]s instances for + * vastly different view hierarchies, such as Desktop Windowing's App Handles and App Headers. + * 2) Pre-warming of the underlying [SurfaceControlViewHostAdapter]s. Useful because their creation + * and first root view assignment are expensive, which is undesirable in latency-sensitive code + * paths like during a shell transition. + */ +class ReusableWindowDecorViewHost( + private val context: Context, + @ShellMainThread private val mainScope: CoroutineScope, + display: Display, + val id: Int, + @VisibleForTesting + val viewHostAdapter: SurfaceControlViewHostAdapter = + SurfaceControlViewHostAdapter(context, display), +) : WindowDecorViewHost, Warmable { + @VisibleForTesting val rootView = FrameLayout(context) + + private var currentUpdateJob: Job? = null + + override val surfaceControl: SurfaceControl + get() = viewHostAdapter.rootSurface + + override fun warmUp() { + if (viewHostAdapter.isInitialized()) { + // Already warmed up. + return + } + Trace.beginSection("$TAG#warmUp") + viewHostAdapter.prepareViewHost(context.resources.configuration, touchableRegion = null) + viewHostAdapter.updateView( + rootView, + WindowManager.LayoutParams( + 0 /* width*/, + 0 /* height */, + TYPE_APPLICATION, + FLAG_NOT_FOCUSABLE or FLAG_SPLIT_TOUCH, + PixelFormat.TRANSPARENT, + ) + .apply { + setTitle("View root of $TAG#$id") + setTrustedOverlay() + }, + ) + Trace.endSection() + } + + override fun updateView( + view: View, + attrs: WindowManager.LayoutParams, + configuration: Configuration, + touchableRegion: Region?, + onDrawTransaction: SurfaceControl.Transaction?, + ) { + Trace.beginSection("ReusableWindowDecorViewHost#updateView") + clearCurrentUpdateJob() + updateViewHost(view, attrs, configuration, touchableRegion, onDrawTransaction) + Trace.endSection() + } + + override fun updateViewAsync( + view: View, + attrs: WindowManager.LayoutParams, + configuration: Configuration, + touchableRegion: Region?, + ) { + Trace.beginSection("ReusableWindowDecorViewHost#updateViewAsync") + clearCurrentUpdateJob() + currentUpdateJob = + mainScope.launch { + updateViewHost( + view, + attrs, + configuration, + touchableRegion, + onDrawTransaction = null, + ) + } + Trace.endSection() + } + + override fun release(t: SurfaceControl.Transaction) { + clearCurrentUpdateJob() + viewHostAdapter.release(t) + } + + private fun updateViewHost( + view: View, + attrs: WindowManager.LayoutParams, + configuration: Configuration, + touchableRegion: Region?, + onDrawTransaction: SurfaceControl.Transaction?, + ) { + Trace.beginSection("ReusableWindowDecorViewHost#updateViewHost") + viewHostAdapter.prepareViewHost(configuration, touchableRegion) + onDrawTransaction?.let { viewHostAdapter.applyTransactionOnDraw(it) } + rootView.removeAllViews() + rootView.addView(view) + viewHostAdapter.updateView(rootView, attrs) + Trace.endSection() + } + + private fun clearCurrentUpdateJob() { + currentUpdateJob?.cancel() + currentUpdateJob = null + } + + companion object { + private const val TAG = "ReusableWindowDecorViewHost" + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/Warmable.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/Warmable.kt new file mode 100644 index 000000000000..2cb0f891436b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/Warmable.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.wm.shell.windowdecor.common.viewhost + +/** + * An interface for an object that can be warmed up before it's needed. + */ +interface Warmable { + fun warmUp() +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java index 329a10998f23..bf03834c70d8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/bar/BubbleBarHandleViewTest.java @@ -15,9 +15,12 @@ */ package com.android.wm.shell.bubbles.bar; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import android.graphics.Color; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -61,4 +64,18 @@ public class BubbleBarHandleViewTest extends ShellTestCase { assertEquals(handleColor, ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_handle_light)); } + + @Test + public void testSetHandleInitialColor_beforeUpdateHandleColor_updatesColor() { + mHandleView.setHandleInitialColor(Color.RED); + assertThat(mHandleView.getHandleColor()).isEqualTo(Color.RED); + } + + @Test + public void testSetHandleInitialColor_afterUpdateHandleColor_doesNotUpdateColor() { + mHandleView.updateHandleColor(/* isRegionDark= */ true, /* animated= */ false); + mHandleView.setHandleInitialColor(Color.RED); + assertThat(mHandleView.getHandleColor()).isEqualTo( + ContextCompat.getColor(mContext, R.color.bubble_bar_expanded_view_handle_light)); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt index 06b805233ee7..667511288bfa 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt @@ -19,9 +19,14 @@ package com.android.wm.shell.compatui.letterbox import android.content.Context import android.graphics.Rect import android.testing.AndroidTestingRunner +import android.view.SurfaceControl import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import java.util.function.Consumer +import kotlin.test.assertEquals +import kotlin.test.assertNull import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any @@ -100,6 +105,35 @@ class LetterboxUtilsTest : ShellTestCase() { } } + @Test + fun `runOnItem executes onFound when an item has been found for a key`() { + runTestScenario { r -> + r.initMap(1 to 2, 3 to 4) + r.runOnItem<Int>(1) + r.verifyOnItemInvoked(expectedItem = 2) + r.verifyOnMissingNotInvoked() + } + } + + @Test + fun `runOnItem executes onMissing when an item has not been found for a key`() { + runTestScenario { r -> + r.initMap(1 to 2, 3 to 4) + r.runOnItem<Int>(8) + r.verifyOnItemNotInvoked() + r.verifyOnMissingInvoked(expectedKey = 8) + } + } + + @Test + fun `moveAndCrop invoked Move and then Crop`() { + runTestScenario { r -> + r.invoke(Rect(1, 2, 51, 62)) + r.verifySetPosition(expectedX = 1f, expectedY = 2f) + r.verifySetWindowCrop(expectedWidth = 50, expectedHeight = 60) + } + } + /** * Runs a test scenario providing a Robot. */ @@ -113,6 +147,14 @@ class LetterboxUtilsTest : ShellTestCase() { builder: (LetterboxSurfaceBuilder) -> LetterboxController ) : LetterboxControllerRobotTest(ctx, builder) { + private var testableMap = mutableMapOf<Int, Int>() + private var onItemState: Int? = null + private var onMissingStateKey: Int? = null + private var onMissingStateMap: MutableMap<Int, Int>? = null + + private val transaction = getTransactionMock() + private val surface = SurfaceControl() + fun verifyCreateSurfaceInvokedWithRequest( target: LetterboxController, times: Int = 1 @@ -147,5 +189,46 @@ class LetterboxUtilsTest : ShellTestCase() { ) { verify(target, times(times)).dump() } + + fun initMap(vararg values: Pair<Int, Int>) = testableMap.putAll(values.toMap()) + + fun <T> runOnItem(key: Int) { + testableMap.runOnItem(key, onFound = { item -> + onItemState = item + }, onMissed = { k, m -> + onMissingStateKey = k + onMissingStateMap = m + }) + } + + fun verifyOnItemInvoked(expectedItem: Int) { + assertEquals(expectedItem, onItemState) + } + + fun verifyOnItemNotInvoked() { + assertNull(onItemState) + } + + fun verifyOnMissingInvoked(expectedKey: Int) { + assertEquals(expectedKey, onMissingStateKey) + assertEquals(onMissingStateMap, testableMap) + } + + fun verifyOnMissingNotInvoked() { + assertNull(onMissingStateKey) + assertNull(onMissingStateMap) + } + + fun invoke(rect: Rect) { + transaction.moveAndCrop(surface, rect) + } + + fun verifySetPosition(expectedX: Float, expectedY: Float) { + verify(transaction).setPosition(surface, expectedX, expectedY) + } + + fun verifySetWindowCrop(expectedWidth: Int, expectedHeight: Int) { + verify(transaction).setWindowCrop(surface, expectedWidth, expectedHeight) + } } } 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 6a4ad2eb6e15..7c9494ce7026 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 @@ -3062,20 +3062,21 @@ class DesktopTasksControllerTest : ShellTestCase() { .thenReturn(DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR) // Drag move the task to the top edge + val currentDragBounds = Rect(100, 50, 500, 1000) spyController.onDragPositioningMove(task, mockSurface, 200f, Rect(100, 200, 500, 1000)) spyController.onDragPositioningEnd( task, mockSurface, Point(100, 50), /* position */ PointF(200f, 300f), /* inputCoordinate */ - Rect(100, 50, 500, 1000), /* currentDragBounds */ + currentDragBounds, Rect(0, 50, 2000, 2000) /* validDragArea */, Rect() /* dragStartBounds */, motionEvent, desktopWindowDecoration) // Assert bounds set to stable bounds - val wct = getLatestToggleResizeDesktopTaskWct() + val wct = getLatestToggleResizeDesktopTaskWct(currentDragBounds) assertThat(findBoundsChange(wct, task)).isEqualTo(STABLE_BOUNDS) // Assert event is properly logged verify(desktopModeEventLogger, times(1)).logTaskResizingStarted( diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt index 6babf817686a..3bcbcbdd9105 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt @@ -257,7 +257,7 @@ class HandleMenuTest : ShellTestCase() { if (splitPosition == SPLIT_POSITION_TOP_OR_LEFT) { (SPLIT_LEFT_BOUNDS.width() / 2) - (HANDLE_WIDTH / 2) } else { - (SPLIT_RIGHT_BOUNDS.width() / 2) - (HANDLE_WIDTH / 2) + SPLIT_LEFT_BOUNDS.width() + (SPLIT_RIGHT_BOUNDS.width() / 2) - (HANDLE_WIDTH / 2) } } else -> error("Invalid windowing mode") diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/DesktopMenuPositionUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/DesktopMenuPositionUtilityTest.kt new file mode 100644 index 000000000000..7b42ff4548ac --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/DesktopMenuPositionUtilityTest.kt @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.windowdecor.common + +import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW +import android.graphics.Rect +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestRunningTaskInfoBuilder +import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT +import com.android.wm.shell.shared.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT +import com.android.wm.shell.splitscreen.SplitScreenController +import org.junit.runner.RunWith +import kotlin.test.Test +import kotlin.test.assertEquals +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +/** + * Tests for [DesktopMenuPositionUtility]. + * + * Build/Install/Run: atest WMShellUnitTests:DesktopMenuPositionUtilityTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class DesktopMenuPositionUtilityTest : ShellTestCase() { + + @Mock private val mockSplitScreenController = mock<SplitScreenController>() + + @Test + fun testFullscreenPositionCalculation() { + val task = setupTaskInfo(WINDOWING_MODE_FULLSCREEN) + val result = + calculateMenuPosition( + splitScreenController = mockSplitScreenController, + taskInfo = task, + MARGIN_START, + MARGIN_TOP, + CAPTION_X, + CAPTION_Y, + CAPTION_WIDTH, + MENU_WIDTH, + isRtl = false, + ) + assertEquals(CAPTION_X + (CAPTION_WIDTH / 2) - (MENU_WIDTH / 2), result.x) + assertEquals(CAPTION_Y + MARGIN_TOP, result.y) + } + + @Test + fun testSplitLeftPositionCalculation() { + val task = setupTaskInfo(WINDOWING_MODE_MULTI_WINDOW) + setupMockSplitScreenController( + splitPosition = SPLIT_POSITION_TOP_OR_LEFT, + isLeftRightSplit = true, + ) + val result = + calculateMenuPosition( + splitScreenController = mockSplitScreenController, + taskInfo = task, + MARGIN_START, + MARGIN_TOP, + CAPTION_X, + CAPTION_Y, + CAPTION_WIDTH, + MENU_WIDTH, + isRtl = false, + ) + assertEquals(CAPTION_X + (CAPTION_WIDTH / 2) - (MENU_WIDTH / 2), result.x) + assertEquals(CAPTION_Y + MARGIN_TOP, result.y) + } + + @Test + fun testSplitRightPositionCalculation() { + val task = setupTaskInfo(WINDOWING_MODE_MULTI_WINDOW) + setupMockSplitScreenController( + splitPosition = SPLIT_POSITION_BOTTOM_OR_RIGHT, + isLeftRightSplit = true, + ) + val result = + calculateMenuPosition( + splitScreenController = mockSplitScreenController, + taskInfo = task, + MARGIN_START, + MARGIN_TOP, + CAPTION_X, + CAPTION_Y, + CAPTION_WIDTH, + MENU_WIDTH, + isRtl = false, + ) + assertEquals( + CAPTION_X + (CAPTION_WIDTH / 2) - (MENU_WIDTH / 2) + SPLIT_LEFT_BOUNDS.width(), + result.x, + ) + assertEquals(CAPTION_Y + MARGIN_TOP, result.y) + } + + @Test + fun testSplitTopPositionCalculation() { + val task = setupTaskInfo(WINDOWING_MODE_MULTI_WINDOW) + setupMockSplitScreenController( + splitPosition = SPLIT_POSITION_TOP_OR_LEFT, + isLeftRightSplit = false, + ) + val result = + calculateMenuPosition( + splitScreenController = mockSplitScreenController, + taskInfo = task, + MARGIN_START, + MARGIN_TOP, + CAPTION_X, + CAPTION_Y, + CAPTION_WIDTH, + MENU_WIDTH, + isRtl = false, + ) + assertEquals(CAPTION_X + (CAPTION_WIDTH / 2) - (MENU_WIDTH / 2), result.x) + assertEquals(CAPTION_Y + MARGIN_TOP, result.y) + } + + @Test + fun testSplitBottomPositionCalculation() { + val task = setupTaskInfo(WINDOWING_MODE_MULTI_WINDOW) + setupMockSplitScreenController( + splitPosition = SPLIT_POSITION_BOTTOM_OR_RIGHT, + isLeftRightSplit = false, + ) + val result = + calculateMenuPosition( + splitScreenController = mockSplitScreenController, + taskInfo = task, + MARGIN_START, + MARGIN_TOP, + CAPTION_X, + CAPTION_Y, + CAPTION_WIDTH, + MENU_WIDTH, + isRtl = false, + ) + assertEquals(CAPTION_X + (CAPTION_WIDTH / 2) - (MENU_WIDTH / 2), result.x) + assertEquals(CAPTION_Y + MARGIN_TOP + SPLIT_TOP_BOUNDS.height(), result.y) + } + + private fun setupTaskInfo(windowingMode: Int): RunningTaskInfo { + return TestRunningTaskInfoBuilder().setWindowingMode(windowingMode).build() + } + + private fun setupMockSplitScreenController(isLeftRightSplit: Boolean, splitPosition: Int) { + whenever(mockSplitScreenController.getSplitPosition(anyInt())).thenReturn(splitPosition) + whenever(mockSplitScreenController.getRefStageBounds(any(), any())).thenAnswer { + (it.arguments.first() as Rect).set( + if (isLeftRightSplit) { + SPLIT_LEFT_BOUNDS + } else { + SPLIT_TOP_BOUNDS + } + ) + (it.arguments[1] as Rect).set( + if (isLeftRightSplit) { + SPLIT_RIGHT_BOUNDS + } else { + SPLIT_BOTTOM_BOUNDS + } + ) + } + whenever(mockSplitScreenController.isLeftRightSplit).thenReturn(isLeftRightSplit) + } + + companion object { + private val SPLIT_LEFT_BOUNDS = Rect(0, 0, 1280, 1600) + private val SPLIT_RIGHT_BOUNDS = Rect(1280, 0, 2560, 1600) + private val SPLIT_TOP_BOUNDS = Rect(0, 0, 2560, 800) + private val SPLIT_BOTTOM_BOUNDS = Rect(0, 800, 2560, 1600) + private const val CAPTION_X = 800 + private const val CAPTION_Y = 50 + private const val MARGIN_START = 30 + private const val MARGIN_TOP = 50 + private const val MENU_WIDTH = 500 + private const val CAPTION_WIDTH = 200 + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/PooledWindowDecorViewHostSupplierTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/PooledWindowDecorViewHostSupplierTest.kt new file mode 100644 index 000000000000..92f5def508c7 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/PooledWindowDecorViewHostSupplierTest.kt @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.common.viewhost + +import android.content.res.Configuration +import android.graphics.Region +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import android.view.SurfaceControl +import android.view.View +import android.view.WindowManager +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.util.StubTransaction +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.mock + +/** + * Tests for [PooledWindowDecorViewHostSupplier]. + * + * Build/Install/Run: atest WMShellUnitTests:PooledWindowDecorViewHostSupplierTest + */ +@SmallTest +@RunWithLooper +@RunWith(AndroidTestingRunner::class) +class PooledWindowDecorViewHostSupplierTest : ShellTestCase() { + + private val testExecutor = TestShellExecutor() + private val testShellInit = ShellInit(testExecutor) + + private lateinit var supplier: PooledWindowDecorViewHostSupplier + + @Test + fun setUp() { + MockitoAnnotations.initMocks(this) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun onInit_warmsAndPoolsViewHosts() = runTest { + supplier = createSupplier(maxPoolSize = 5, preWarmSize = 2) + + testExecutor.flushAll() + advanceUntilIdle() + + val viewHost1 = supplier.acquire(context, context.display) as ReusableWindowDecorViewHost + val viewHost2 = supplier.acquire(context, context.display) as ReusableWindowDecorViewHost + + // Acquired warmed up view hosts from the pool. + assertThat(viewHost1.viewHostAdapter.isInitialized()).isTrue() + assertThat(viewHost2.viewHostAdapter.isInitialized()).isTrue() + } + + @Test(expected = Throwable::class) + fun onInit_warmUpSizeExceedsPoolSize_throws() = runTest { + createSupplier(maxPoolSize = 3, preWarmSize = 4) + } + + @Test + fun acquire_poolBelowLimit_caches() = runTest { + supplier = createSupplier(maxPoolSize = 5) + + val viewHost = FakeWindowDecorViewHost() + supplier.release(viewHost, StubTransaction()) + + assertThat(supplier.acquire(context, context.display)).isEqualTo(viewHost) + } + + @Test + fun release_poolBelowLimit_doesNotReleaseViewHost() = runTest { + supplier = createSupplier(maxPoolSize = 5) + + val viewHost = FakeWindowDecorViewHost() + val mockT = mock<SurfaceControl.Transaction>() + supplier.release(viewHost, mockT) + + assertThat(viewHost.released).isFalse() + } + + @Test + fun release_poolAtLimit_doesNotCache() = runTest { + supplier = createSupplier(maxPoolSize = 1) + val viewHost = FakeWindowDecorViewHost() + supplier.release(viewHost, StubTransaction()) // Maxes pool. + + val viewHost2 = FakeWindowDecorViewHost() + supplier.release(viewHost2, StubTransaction()) // Beyond limit. + + assertThat(supplier.acquire(context, context.display)).isEqualTo(viewHost) + // Second one wasn't cached, so the acquired one should've been a new instance. + assertThat(supplier.acquire(context, context.display)).isNotEqualTo(viewHost2) + } + + @Test + fun release_poolAtLimit_releasesViewHost() = runTest { + supplier = createSupplier(maxPoolSize = 1) + val viewHost = FakeWindowDecorViewHost() + supplier.release(viewHost, StubTransaction()) // Maxes pool. + + val viewHost2 = FakeWindowDecorViewHost() + val mockT = mock<SurfaceControl.Transaction>() + supplier.release(viewHost2, mockT) // Beyond limit. + + // Second one doesn't fit, so it needs to be released. + assertThat(viewHost2.released).isTrue() + } + + private fun CoroutineScope.createSupplier(maxPoolSize: Int, preWarmSize: Int = 0) = + PooledWindowDecorViewHostSupplier(context, this, testShellInit, maxPoolSize, preWarmSize) + .also { testShellInit.init() } + + private class FakeWindowDecorViewHost : WindowDecorViewHost { + var released = false + private set + + override val surfaceControl: SurfaceControl + get() = SurfaceControl() + + override fun updateView( + view: View, + attrs: WindowManager.LayoutParams, + configuration: Configuration, + touchableRegion: Region?, + onDrawTransaction: SurfaceControl.Transaction?, + ) {} + + override fun updateViewAsync( + view: View, + attrs: WindowManager.LayoutParams, + configuration: Configuration, + touchableRegion: Region?, + ) {} + + override fun release(t: SurfaceControl.Transaction) { + released = true + } + } +} 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 new file mode 100644 index 000000000000..d99a4825e580 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/common/viewhost/ReusableWindowDecorViewHostTest.kt @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.common.viewhost + +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.SurfaceControl +import android.view.View +import android.view.WindowManager +import androidx.test.filters.SmallTest +import com.android.wm.shell.ShellTestCase +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.advanceUntilIdle +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import org.mockito.kotlin.spy +import org.mockito.kotlin.verify + +/** + * Tests for [ReusableWindowDecorViewHost]. + * + * Build/Install/Run: atest WMShellUnitTests:ReusableWindowDecorViewHostTest + */ +@SmallTest +@TestableLooper.RunWithLooper +@RunWith(AndroidTestingRunner::class) +class ReusableWindowDecorViewHostTest : ShellTestCase() { + + @Test + fun update_differentView_replacesView() = runTest { + val view = View(context) + val lp = WindowManager.LayoutParams() + val reusableVH = createReusableViewHost() + reusableVH.updateView(view, lp, context.resources.configuration, null) + + assertThat(reusableVH.rootView.childCount).isEqualTo(1) + assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(view) + + val newView = View(context) + val newLp = WindowManager.LayoutParams() + reusableVH.updateView(newView, newLp, context.resources.configuration, null) + + assertThat(reusableVH.rootView.childCount).isEqualTo(1) + assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(newView) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun updateView_clearsPendingAsyncJob() = runTest { + val reusableVH = createReusableViewHost() + val asyncView = View(context) + val syncView = View(context) + val asyncAttrs = WindowManager.LayoutParams(100, 100) + val syncAttrs = WindowManager.LayoutParams(200, 200) + + reusableVH.updateViewAsync( + view = asyncView, + attrs = asyncAttrs, + configuration = context.resources.configuration, + ) + + // No view host yet, since the coroutine hasn't run. + assertThat(reusableVH.viewHostAdapter.isInitialized()).isFalse() + + reusableVH.updateView( + view = syncView, + attrs = syncAttrs, + configuration = context.resources.configuration, + onDrawTransaction = null, + ) + + // Would run coroutine if it hadn't been cancelled. + advanceUntilIdle() + + 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(reusableVH.view()!!.layoutParams.width).isEqualTo(syncAttrs.width) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun updateViewAsync() = runTest { + val reusableVH = createReusableViewHost() + val view = View(context) + val attrs = WindowManager.LayoutParams(100, 100) + + reusableVH.updateViewAsync( + view = view, + attrs = attrs, + configuration = context.resources.configuration, + ) + + assertThat(reusableVH.viewHostAdapter.isInitialized()).isFalse() + + advanceUntilIdle() + + assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue() + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun updateViewAsync_clearsPendingAsyncJob() = runTest { + val reusableVH = createReusableViewHost() + + val view = View(context) + reusableVH.updateViewAsync( + view = view, + attrs = WindowManager.LayoutParams(100, 100), + configuration = context.resources.configuration, + ) + val otherView = View(context) + reusableVH.updateViewAsync( + view = otherView, + attrs = WindowManager.LayoutParams(100, 100), + configuration = context.resources.configuration, + ) + + advanceUntilIdle() + + assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue() + assertThat(reusableVH.rootView.getChildAt(0)).isEqualTo(otherView) + } + + @Test + fun release() = runTest { + val reusableVH = createReusableViewHost() + + val view = View(context) + reusableVH.updateView( + view = view, + attrs = WindowManager.LayoutParams(100, 100), + configuration = context.resources.configuration, + onDrawTransaction = null, + ) + + val t = mock(SurfaceControl.Transaction::class.java) + reusableVH.release(t) + + verify(reusableVH.viewHostAdapter).release(t) + } + + @Test + fun warmUp_addsRootView() = runTest { + val reusableVH = createReusableViewHost().apply { warmUp() } + + assertThat(reusableVH.viewHostAdapter.isInitialized()).isTrue() + assertThat(reusableVH.view()).isEqualTo(reusableVH.rootView) + } + + private fun CoroutineScope.createReusableViewHost() = + ReusableWindowDecorViewHost( + context = context, + mainScope = this, + display = context.display, + id = 1, + viewHostAdapter = spy(SurfaceControlViewHostAdapter(context, context.display)), + ) + + private fun ReusableWindowDecorViewHost.view(): View? = viewHostAdapter.viewHost?.view +} diff --git a/libs/hwui/jni/text/TextShaper.cpp b/libs/hwui/jni/text/TextShaper.cpp index c73598960551..d1782b285b34 100644 --- a/libs/hwui/jni/text/TextShaper.cpp +++ b/libs/hwui/jni/text/TextShaper.cpp @@ -225,8 +225,8 @@ static jboolean TextShaper_Result_getFakeItalic(CRITICAL_JNI_PARAMS_COMMA jlong constexpr float NO_OVERRIDE = -1; -float findValueFromVariationSettings(const minikin::FontFakery& fakery, minikin::AxisTag tag) { - for (const minikin::FontVariation& fv : fakery.variationSettings()) { +float findValueFromVariationSettings(const minikin::VariationSettings& axes, minikin::AxisTag tag) { + for (const minikin::FontVariation& fv : axes) { if (fv.axisTag == tag) { return fv.value; } @@ -238,8 +238,8 @@ float findValueFromVariationSettings(const minikin::FontFakery& fakery, minikin: static jfloat TextShaper_Result_getWeightOverride(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) { const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr); if (text_feature::typeface_redesign_readonly()) { - float value = - findValueFromVariationSettings(layout->layout.getFakery(i), minikin::TAG_wght); + float value = findValueFromVariationSettings(layout->layout.typeface(i)->GetAxes(), + minikin::TAG_wght); return std::isnan(value) ? NO_OVERRIDE : value; } else { return layout->layout.getFakery(i).wghtAdjustment(); @@ -250,8 +250,8 @@ static jfloat TextShaper_Result_getWeightOverride(CRITICAL_JNI_PARAMS_COMMA jlon static jfloat TextShaper_Result_getItalicOverride(CRITICAL_JNI_PARAMS_COMMA jlong ptr, jint i) { const LayoutWrapper* layout = reinterpret_cast<LayoutWrapper*>(ptr); if (text_feature::typeface_redesign_readonly()) { - float value = - findValueFromVariationSettings(layout->layout.getFakery(i), minikin::TAG_ital); + float value = findValueFromVariationSettings(layout->layout.typeface(i)->GetAxes(), + minikin::TAG_ital); return std::isnan(value) ? NO_OVERRIDE : value; } else { return layout->layout.getFakery(i).italAdjustment(); diff --git a/location/api/system-current.txt b/location/api/system-current.txt index 9478e350de57..ba4224137cd4 100644 --- a/location/api/system-current.txt +++ b/location/api/system-current.txt @@ -6,6 +6,111 @@ package android.location { method public void onLocationBatch(java.util.List<android.location.Location>); } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class BeidouAssistance implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.location.GnssAlmanac getAlmanac(); + method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel(); + method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel(); + method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels(); + method @NonNull public java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections> getSatelliteCorrections(); + method @NonNull public java.util.List<android.location.BeidouSatelliteEphemeris> getSatelliteEphemeris(); + method @NonNull public java.util.List<android.location.TimeModel> getTimeModels(); + method @Nullable public android.location.UtcModel getUtcModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.BeidouAssistance> CREATOR; + } + + public static final class BeidouAssistance.Builder { + ctor public BeidouAssistance.Builder(); + method @NonNull public android.location.BeidouAssistance build(); + method @NonNull public android.location.BeidouAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac); + method @NonNull public android.location.BeidouAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel); + method @NonNull public android.location.BeidouAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel); + method @NonNull public android.location.BeidouAssistance.Builder setRealTimeIntegrityModels(@Nullable java.util.List<android.location.RealTimeIntegrityModel>); + method @NonNull public android.location.BeidouAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.BeidouAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.BeidouSatelliteEphemeris>); + method @NonNull public android.location.BeidouAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.BeidouAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class BeidouSatelliteEphemeris implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=1, to=63) public int getPrn(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel getSatelliteClockModel(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime getSatelliteEphemerisTime(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteHealth getSatelliteHealth(); + method @NonNull public android.location.KeplerianOrbitModel getSatelliteOrbitModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.BeidouSatelliteEphemeris> CREATOR; + } + + public static final class BeidouSatelliteEphemeris.BeidouSatelliteClockModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-0.00977F, to=0.00977f) public double getAf0(); + method @FloatRange(from=-1.87E-9F, to=1.87E-9f) public double getAf1(); + method @FloatRange(from=-1.39E-17F, to=1.39E-17f) public double getAf2(); + method @IntRange(from=0, to=31) public int getAodc(); + method @FloatRange(from=-5.12E-8F, to=5.12E-8f) public double getTgd1(); + method @FloatRange(from=-5.12E-8F, to=5.12E-8f) public double getTgd2(); + method @IntRange(from=0) public long getTimeOfClockSeconds(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel> CREATOR; + } + + public static final class BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder { + ctor public BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel build(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder setAf0(@FloatRange(from=-0.00977F, to=0.00977f) double); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder setAf1(@FloatRange(from=-1.87E-9F, to=1.87E-9f) double); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder setAf2(@FloatRange(from=-1.39E-17F, to=1.39E-17f) double); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder setAodc(@IntRange(from=0, to=31) int); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder setTgd1(@FloatRange(from=-5.12E-8F, to=5.12E-8f) double); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder setTgd2(@FloatRange(from=-5.12E-8F, to=5.12E-8f) double); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel.Builder setTimeOfClockSeconds(@IntRange(from=0) long); + } + + public static final class BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0) public int getBeidouWeekNumber(); + method @IntRange(from=0, to=31) public int getIode(); + method @IntRange(from=0, to=604792) public int getToeSeconds(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime> CREATOR; + } + + public static final class BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder { + ctor public BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime build(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder setBeidouWeekNumber(@IntRange(from=0) int); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder setIode(int); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime.Builder setToeSeconds(@IntRange(from=0, to=604792) int); + } + + public static final class BeidouSatelliteEphemeris.BeidouSatelliteHealth implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0, to=1) public int getSatH1(); + method @FloatRange(from=0.0f, to=8192.0f) public double getSvAccur(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.BeidouSatelliteEphemeris.BeidouSatelliteHealth> CREATOR; + } + + public static final class BeidouSatelliteEphemeris.BeidouSatelliteHealth.Builder { + ctor public BeidouSatelliteEphemeris.BeidouSatelliteHealth.Builder(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteHealth build(); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteHealth.Builder setSatH1(int); + method @NonNull public android.location.BeidouSatelliteEphemeris.BeidouSatelliteHealth.Builder setSvAccur(double); + } + + public static final class BeidouSatelliteEphemeris.Builder { + ctor public BeidouSatelliteEphemeris.Builder(); + method @NonNull public android.location.BeidouSatelliteEphemeris build(); + method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setPrn(int); + method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSatelliteClockModel(@NonNull android.location.BeidouSatelliteEphemeris.BeidouSatelliteClockModel); + method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSatelliteEphemerisTime(@NonNull android.location.BeidouSatelliteEphemeris.BeidouSatelliteEphemerisTime); + method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSatelliteHealth(@NonNull android.location.BeidouSatelliteEphemeris.BeidouSatelliteHealth); + method @NonNull public android.location.BeidouSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.KeplerianOrbitModel); + } + public final class CorrelationVector implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=0.0f) public double getFrequencyOffsetMetersPerSecond(); @@ -43,12 +148,375 @@ package android.location { method public void unregisterCountryDetectorCallback(@NonNull java.util.function.Consumer<android.location.Country>); } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GalileoAssistance implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.location.GnssAlmanac getAlmanac(); + method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel(); + method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel(); + method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels(); + method @NonNull public java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections> getSatelliteCorrections(); + method @NonNull public java.util.List<android.location.GalileoSatelliteEphemeris> getSatelliteEphemeris(); + method @NonNull public java.util.List<android.location.TimeModel> getTimeModels(); + method @Nullable public android.location.UtcModel getUtcModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GalileoAssistance> CREATOR; + } + + public static final class GalileoAssistance.Builder { + ctor public GalileoAssistance.Builder(); + method @NonNull public android.location.GalileoAssistance build(); + method @NonNull public android.location.GalileoAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac); + method @NonNull public android.location.GalileoAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel); + method @NonNull public android.location.GalileoAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel); + method @NonNull public android.location.GalileoAssistance.Builder setRealTimeIntegrityModels(@Nullable java.util.List<android.location.RealTimeIntegrityModel>); + method @NonNull public android.location.GalileoAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.GalileoAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.GalileoSatelliteEphemeris>); + method @NonNull public android.location.GalileoAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.GalileoAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GalileoIonosphericModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=0.0f, to=512.0f) public double getAi0(); + method @FloatRange(from=-4.0F, to=4.0f) public double getAi1(); + method @FloatRange(from=-0.5F, to=0.5f) public double getAi2(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GalileoIonosphericModel> CREATOR; + } + + public static final class GalileoIonosphericModel.Builder { + ctor public GalileoIonosphericModel.Builder(); + method @NonNull public android.location.GalileoIonosphericModel build(); + method @NonNull public android.location.GalileoIonosphericModel.Builder setAi0(@FloatRange(from=0.0f, to=512.0f) double); + method @NonNull public android.location.GalileoIonosphericModel.Builder setAi1(@FloatRange(from=-4.0F, to=4.0f) double); + method @NonNull public android.location.GalileoIonosphericModel.Builder setAi2(@FloatRange(from=-0.5F, to=0.5f) double); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GalileoSatelliteEphemeris implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel> getSatelliteClockModels(); + method @IntRange(from=1, to=36) public int getSatelliteCodeNumber(); + method @NonNull public android.location.SatelliteEphemerisTime getSatelliteEphemerisTime(); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth getSatelliteHealth(); + method @NonNull public android.location.KeplerianOrbitModel getSatelliteOrbitModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GalileoSatelliteEphemeris> CREATOR; + } + + public static final class GalileoSatelliteEphemeris.Builder { + ctor public GalileoSatelliteEphemeris.Builder(); + method @NonNull public android.location.GalileoSatelliteEphemeris build(); + method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteClockModels(@NonNull java.util.List<android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel>); + method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteCodeNumber(@IntRange(from=1, to=36) int); + method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteEphemerisTime(@NonNull android.location.SatelliteEphemerisTime); + method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteHealth(@NonNull android.location.GalileoSatelliteEphemeris.GalileoSvHealth); + method @NonNull public android.location.GalileoSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.KeplerianOrbitModel); + } + + public static final class GalileoSatelliteEphemeris.GalileoSatelliteClockModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-0.0625F, to=0.0625f) public double getAf0(); + method @FloatRange(from=-1.5E-8F, to=1.5E-8f) public double getAf1(); + method @FloatRange(from=-5.56E-17F, to=5.56E-17f) public double getAf2(); + method @FloatRange(from=-1.2E-7F, to=1.2E-7f) public double getBgdSeconds(); + method public int getSatelliteClockType(); + method @FloatRange(from=0.0f) public double getSisaMeters(); + method @IntRange(from=0) public long getTimeOfClockSeconds(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel> CREATOR; + field public static final int TYPE_FNAV = 1; // 0x1 + field public static final int TYPE_INAV = 2; // 0x2 + field public static final int TYPE_UNDEFINED = 0; // 0x0 + } + + public static final class GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder { + ctor public GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder(); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel build(); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder setAf0(@FloatRange(from=-0.0625F, to=0.0625f) double); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder setAf1(@FloatRange(from=-1.5E-8F, to=1.5E-8f) double); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder setAf2(@FloatRange(from=-5.56E-17F, to=5.56E-17f) double); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder setBgdSeconds(@FloatRange(from=-1.2E-7F, to=1.2E-7f) double); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder setSatelliteClockType(int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder setSisaMeters(@FloatRange(from=0.0f) double); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSatelliteClockModel.Builder setTimeOfClockSeconds(@IntRange(from=0) long); + } + + public static final class GalileoSatelliteEphemeris.GalileoSvHealth implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0, to=1) public int getDataValidityStatusE1b(); + method @IntRange(from=0, to=1) public int getDataValidityStatusE5a(); + method @IntRange(from=0, to=1) public int getDataValidityStatusE5b(); + method @IntRange(from=0, to=3) public int getSignalHealthStatusE1b(); + method @IntRange(from=0, to=3) public int getSignalHealthStatusE5a(); + method @IntRange(from=0, to=3) public int getSignalHealthStatusE5b(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GalileoSatelliteEphemeris.GalileoSvHealth> CREATOR; + } + + public static final class GalileoSatelliteEphemeris.GalileoSvHealth.Builder { + ctor public GalileoSatelliteEphemeris.GalileoSvHealth.Builder(); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth build(); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE1b(@IntRange(from=0, to=1) int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE5a(@IntRange(from=0, to=1) int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setDataValidityStatusE5b(@IntRange(from=0, to=1) int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE1b(@IntRange(from=0, to=3) int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE5a(@IntRange(from=0, to=3) int); + method @NonNull public android.location.GalileoSatelliteEphemeris.GalileoSvHealth.Builder setSignalHealthStatusE5b(@IntRange(from=0, to=3) int); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GlonassAlmanac implements android.os.Parcelable { + ctor public GlonassAlmanac(@IntRange(from=0) long, @NonNull java.util.List<android.location.GlonassAlmanac.GlonassSatelliteAlmanac>); + method public int describeContents(); + method @IntRange(from=0) public long getIssueDateMillis(); + method @NonNull public java.util.List<android.location.GlonassAlmanac.GlonassSatelliteAlmanac> getSatelliteAlmanacs(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassAlmanac> CREATOR; + } + + public static final class GlonassAlmanac.GlonassSatelliteAlmanac implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-0.067F, to=0.067f) public double getDeltaI(); + method @FloatRange(from=-3600.0F, to=3600.0f) public double getDeltaT(); + method @FloatRange(from=-0.004F, to=0.004f) public double getDeltaTDot(); + method @FloatRange(from=0.0f, to=0.03f) public double getEccentricity(); + method @IntRange(from=0, to=31) public int getFreqChannel(); + method @FloatRange(from=-1.0F, to=1.0f) public double getLambda(); + method @FloatRange(from=-1.0F, to=1.0f) public double getOmega(); + method @IntRange(from=1, to=25) public int getSlotNumber(); + method @IntRange(from=0, to=1) public int getSvHealth(); + method @FloatRange(from=0.0f, to=44100.0f) public double getTLambda(); + method @FloatRange(from=-0.0019F, to=0.0019f) public double getTau(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassAlmanac.GlonassSatelliteAlmanac> CREATOR; + } + + public static final class GlonassAlmanac.GlonassSatelliteAlmanac.Builder { + ctor public GlonassAlmanac.GlonassSatelliteAlmanac.Builder(); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac build(); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setDeltaI(@FloatRange(from=-0.067F, to=0.067f) double); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setDeltaT(@FloatRange(from=-3600.0F, to=3600.0f) double); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setDeltaTDot(@FloatRange(from=-0.004F, to=0.004f) double); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setEccentricity(@FloatRange(from=0.0f, to=0.03f) double); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setFreqChannel(@IntRange(from=0, to=31) int); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setLambda(@FloatRange(from=-1.0F, to=1.0f) double); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setOmega(@FloatRange(from=-1.0F, to=1.0f) double); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setSlotNumber(@IntRange(from=1, to=25) int); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setSvHealth(@IntRange(from=0, to=1) int); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setTLambda(@FloatRange(from=0.0f, to=44100.0f) double); + method @NonNull public android.location.GlonassAlmanac.GlonassSatelliteAlmanac.Builder setTau(@FloatRange(from=-0.0019F, to=0.0019f) double); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GlonassAssistance implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.location.GlonassAlmanac getAlmanac(); + method @NonNull public java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections> getSatelliteCorrections(); + method @NonNull public java.util.List<android.location.GlonassSatelliteEphemeris> getSatelliteEphemeris(); + method @NonNull public java.util.List<android.location.TimeModel> getTimeModels(); + method @Nullable public android.location.UtcModel getUtcModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassAssistance> CREATOR; + } + + public static final class GlonassAssistance.Builder { + ctor public GlonassAssistance.Builder(); + method @NonNull public android.location.GlonassAssistance build(); + method @NonNull public android.location.GlonassAssistance.Builder setAlmanac(@Nullable android.location.GlonassAlmanac); + method @NonNull public android.location.GlonassAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.GlonassAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.GlonassSatelliteEphemeris>); + method @NonNull public android.location.GlonassAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.GlonassAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GlonassSatelliteEphemeris implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0, to=31) public int getAgeInDays(); + method @FloatRange(from=0.0f) public double getFrameTimeSeconds(); + method @IntRange(from=0, to=1) public int getHealthState(); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel getSatelliteClockModel(); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel getSatelliteOrbitModel(); + method @IntRange(from=1, to=25) public int getSlotNumber(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassSatelliteEphemeris> CREATOR; + } + + public static final class GlonassSatelliteEphemeris.Builder { + ctor public GlonassSatelliteEphemeris.Builder(); + method @NonNull public android.location.GlonassSatelliteEphemeris build(); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setAgeInDays(@IntRange(from=0, to=31) int); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setFrameTimeSeconds(@FloatRange(from=0.0f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setHealthState(@IntRange(from=0, to=1) int); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setSatelliteClockModel(@NonNull android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel); + method @NonNull public android.location.GlonassSatelliteEphemeris.Builder setSlotNumber(@IntRange(from=1, to=25) int); + } + + public static final class GlonassSatelliteEphemeris.GlonassSatelliteClockModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-0.002F, to=0.002f) public double getClockBias(); + method @FloatRange(from=-9.32E-10F, to=9.32E-10f) public double getFrequencyBias(); + method @IntRange(from=0xfffffff9, to=6) public int getFrequencyNumber(); + method @IntRange(from=0) public long getTimeOfClockSeconds(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel> CREATOR; + } + + public static final class GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder { + ctor public GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder(); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel build(); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setClockBias(@FloatRange(from=-0.002F, to=0.002f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setFrequencyBias(@FloatRange(from=-9.32E-10F, to=9.32E-10f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setFrequencyNumber(@IntRange(from=0xfffffff9, to=6) int); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteClockModel.Builder setTimeOfClockSeconds(@IntRange(from=0) long); + } + + public static final class GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-27000.0F, to=27000.0f) public double getX(); + method @FloatRange(from=-6.2E-9F, to=6.2E-9f) public double getXAccel(); + method @FloatRange(from=-4.3F, to=4.3f) public double getXDot(); + method @FloatRange(from=-27000.0F, to=27000.0f) public double getY(); + method @FloatRange(from=-6.2E-9F, to=6.2E-9f) public double getYAccel(); + method @FloatRange(from=-4.3F, to=4.3f) public double getYDot(); + method @FloatRange(from=-27000.0F, to=27000.0f) public double getZ(); + method @FloatRange(from=-6.2E-9F, to=6.2E-9f) public double getZAccel(); + method @FloatRange(from=-4.3F, to=4.3f) public double getZDot(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel> CREATOR; + } + + public static final class GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder { + ctor public GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder(); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel build(); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setX(@FloatRange(from=-27000.0F, to=27000.0f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setXAccel(@FloatRange(from=-6.2E-9F, to=6.2E-9f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setXDot(@FloatRange(from=-4.3F, to=4.3f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setY(@FloatRange(from=-27000.0F, to=27000.0f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setYAccel(@FloatRange(from=-6.2E-9F, to=6.2E-9f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setYDot(@FloatRange(from=-4.3F, to=4.3f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setZ(@FloatRange(from=-27000.0F, to=27000.0f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setZAccel(@FloatRange(from=-6.2E-9F, to=6.2E-9f) double); + method @NonNull public android.location.GlonassSatelliteEphemeris.GlonassSatelliteOrbitModel.Builder setZDot(@FloatRange(from=-4.3F, to=4.3f) double); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GnssAlmanac implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<android.location.GnssAlmanac.GnssSatelliteAlmanac> getGnssSatelliteAlmanacs(); + method @IntRange(from=0) public int getIod(); + method @IntRange(from=0) public long getIssueDateMillis(); + method @IntRange(from=0, to=604800) public int getToaSeconds(); + method @IntRange(from=0) public int getWeekNumber(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAlmanac> CREATOR; + } + + public static final class GnssAlmanac.Builder { + ctor public GnssAlmanac.Builder(); + method @NonNull public android.location.GnssAlmanac build(); + method @NonNull public android.location.GnssAlmanac.Builder setGnssSatelliteAlmanacs(@NonNull java.util.List<android.location.GnssAlmanac.GnssSatelliteAlmanac>); + method @NonNull public android.location.GnssAlmanac.Builder setIod(@IntRange(from=0) int); + method @NonNull public android.location.GnssAlmanac.Builder setIssueDateMillis(@IntRange(from=0) long); + method @NonNull public android.location.GnssAlmanac.Builder setToaSeconds(@IntRange(from=0, to=604800) int); + method @NonNull public android.location.GnssAlmanac.Builder setWeekNumber(@IntRange(from=0) int); + } + + public static final class GnssAlmanac.GnssSatelliteAlmanac implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-0.0625F, to=0.0625f) public double getAf0(); + method @FloatRange(from=-1.5E-8F, to=1.5E-8f) public double getAf1(); + method @FloatRange(from=0.0f) public double getEccentricity(); + method @FloatRange(from=-1.0F, to=1.0f) public double getInclination(); + method @FloatRange(from=-1.0F, to=1.0f) public double getM0(); + method @FloatRange(from=-1.0F, to=1.0f) public double getOmega(); + method @FloatRange(from=-1.0F, to=1.0f) public double getOmega0(); + method @FloatRange(from=-1.0F, to=1.0f) public double getOmegaDot(); + method @FloatRange(from=0.0f, to=8192.0f) public double getRootA(); + method @IntRange(from=0) public int getSvHealth(); + method @IntRange(from=1) public int getSvid(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAlmanac.GnssSatelliteAlmanac> CREATOR; + } + + public static final class GnssAlmanac.GnssSatelliteAlmanac.Builder { + ctor public GnssAlmanac.GnssSatelliteAlmanac.Builder(); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac build(); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setAf0(@FloatRange(from=-0.0625F, to=0.0625f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setAf1(@FloatRange(from=-1.5E-8F, to=1.5E-8f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setEccentricity(@FloatRange(from=0.0f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setInclination(@FloatRange(from=-1.0F, to=1.0f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setM0(@FloatRange(from=-1.0F, to=1.0f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setOmega(@FloatRange(from=-1.0F, to=1.0f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setOmega0(@FloatRange(from=-1.0F, to=1.0f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setOmegaDot(@FloatRange(from=-1.0F, to=1.0f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setRootA(@FloatRange(from=0.0f, to=8192.0f) double); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setSvHealth(@IntRange(from=0) int); + method @NonNull public android.location.GnssAlmanac.GnssSatelliteAlmanac.Builder setSvid(@IntRange(from=1) int); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GnssAssistance implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.location.BeidouAssistance getBeidouAssistance(); + method @Nullable public android.location.GalileoAssistance getGalileoAssistance(); + method @Nullable public android.location.GlonassAssistance getGlonassAssistance(); + method @Nullable public android.location.GpsAssistance getGpsAssistance(); + method @Nullable public android.location.QzssAssistance getQzssAssistance(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAssistance> CREATOR; + } + + public static final class GnssAssistance.Builder { + ctor public GnssAssistance.Builder(); + method @NonNull public android.location.GnssAssistance build(); + method @NonNull public android.location.GnssAssistance.Builder setBeidouAssistance(@Nullable android.location.BeidouAssistance); + method @NonNull public android.location.GnssAssistance.Builder setGalileoAssistance(@Nullable android.location.GalileoAssistance); + method @NonNull public android.location.GnssAssistance.Builder setGlonassAssistance(@Nullable android.location.GlonassAssistance); + method @NonNull public android.location.GnssAssistance.Builder setGpsAssistance(@Nullable android.location.GpsAssistance); + method @NonNull public android.location.GnssAssistance.Builder setQzssAssistance(@Nullable android.location.QzssAssistance); + } + + public static final class GnssAssistance.GnssSatelliteCorrections implements android.os.Parcelable { + ctor public GnssAssistance.GnssSatelliteCorrections(@IntRange(from=1, to=206) int, @NonNull java.util.List<android.location.IonosphericCorrection>); + method public int describeContents(); + method @NonNull public java.util.List<android.location.IonosphericCorrection> getIonosphericCorrections(); + method @IntRange(from=1, to=206) public int getSvid(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssAssistance.GnssSatelliteCorrections> CREATOR; + } + public final class GnssCapabilities implements android.os.Parcelable { method @Deprecated public boolean hasMeasurementCorrectionsReflectingPane(); method @Deprecated public boolean hasNavMessages(); method @Deprecated public boolean hasSatelliteBlacklist(); } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GnssCorrectionComponent implements android.os.Parcelable { + ctor public GnssCorrectionComponent(@NonNull String, @NonNull android.location.GnssCorrectionComponent.GnssInterval, @NonNull android.location.GnssCorrectionComponent.PseudorangeCorrection); + method public int describeContents(); + method @NonNull public android.location.GnssCorrectionComponent.PseudorangeCorrection getPseudorangeCorrection(); + method @NonNull public String getSourceKey(); + method @NonNull public android.location.GnssCorrectionComponent.GnssInterval getValidityInterval(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCorrectionComponent> CREATOR; + } + + public static final class GnssCorrectionComponent.GnssInterval implements android.os.Parcelable { + ctor public GnssCorrectionComponent.GnssInterval(@IntRange(from=0) long, @IntRange(from=0) long); + method public int describeContents(); + method @IntRange(from=0) public long getEndMillisSinceGpsEpoch(); + method @IntRange(from=0) public long getStartMillisSinceGpsEpoch(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCorrectionComponent.GnssInterval> CREATOR; + } + + public static final class GnssCorrectionComponent.PseudorangeCorrection implements android.os.Parcelable { + ctor public GnssCorrectionComponent.PseudorangeCorrection(double, double, double); + method public int describeContents(); + method public double getCorrectionMeters(); + method public double getCorrectionRateMetersPerSecond(); + method @FloatRange(from=0.0f) public double getCorrectionUncertaintyMeters(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssCorrectionComponent.PseudorangeCorrection> CREATOR; + } + public final class GnssExcessPathInfo implements android.os.Parcelable { method public int describeContents(); method @FloatRange(from=0.0f) public float getAttenuationDb(); @@ -193,6 +661,33 @@ package android.location { method @NonNull public android.location.GnssSingleSatCorrection.Builder setSatelliteId(@IntRange(from=0) int); } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GpsAssistance implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.location.GnssAlmanac getAlmanac(); + method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel(); + method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel(); + method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels(); + method @NonNull public java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections> getSatelliteCorrections(); + method @NonNull public java.util.List<android.location.GpsSatelliteEphemeris> getSatelliteEphemeris(); + method @NonNull public java.util.List<android.location.TimeModel> getTimeModels(); + method @Nullable public android.location.UtcModel getUtcModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GpsAssistance> CREATOR; + } + + public static final class GpsAssistance.Builder { + ctor public GpsAssistance.Builder(); + method @NonNull public android.location.GpsAssistance build(); + method @NonNull public android.location.GpsAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac); + method @NonNull public android.location.GpsAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel); + method @NonNull public android.location.GpsAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel); + method @NonNull public android.location.GpsAssistance.Builder setRealTimeIntegrityModels(@Nullable java.util.List<android.location.RealTimeIntegrityModel>); + method @NonNull public android.location.GpsAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.GpsAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.GpsSatelliteEphemeris>); + method @NonNull public android.location.GpsAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.GpsAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); + } + @Deprecated public class GpsClock implements android.os.Parcelable { method @Deprecated public int describeContents(); method @Deprecated public double getBiasInNs(); @@ -418,6 +913,174 @@ package android.location { method @Deprecated public void onStatusChanged(int); } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class GpsSatelliteEphemeris implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsL2Params getGpsL2Params(); + method @IntRange(from=1, to=32) public int getPrn(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel getSatelliteClockModel(); + method @NonNull public android.location.SatelliteEphemerisTime getSatelliteEphemerisTime(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteHealth getSatelliteHealth(); + method @NonNull public android.location.KeplerianOrbitModel getSatelliteOrbitModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GpsSatelliteEphemeris> CREATOR; + } + + public static final class GpsSatelliteEphemeris.Builder { + ctor public GpsSatelliteEphemeris.Builder(); + method @NonNull public android.location.GpsSatelliteEphemeris build(); + method @NonNull public android.location.GpsSatelliteEphemeris.Builder setGpsL2Params(@NonNull android.location.GpsSatelliteEphemeris.GpsL2Params); + method @NonNull public android.location.GpsSatelliteEphemeris.Builder setPrn(@IntRange(from=1, to=32) int); + method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSatelliteClockModel(@NonNull android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel); + method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSatelliteEphemerisTime(@NonNull android.location.SatelliteEphemerisTime); + method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSatelliteHealth(@NonNull android.location.GpsSatelliteEphemeris.GpsSatelliteHealth); + method @NonNull public android.location.GpsSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.KeplerianOrbitModel); + } + + public static final class GpsSatelliteEphemeris.GpsL2Params implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0, to=3) public int getL2Code(); + method @IntRange(from=0, to=1) public int getL2Flag(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GpsSatelliteEphemeris.GpsL2Params> CREATOR; + } + + public static final class GpsSatelliteEphemeris.GpsL2Params.Builder { + ctor public GpsSatelliteEphemeris.GpsL2Params.Builder(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsL2Params build(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsL2Params.Builder setL2Code(@IntRange(from=0, to=3) int); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsL2Params.Builder setL2Flag(@IntRange(from=0, to=1) int); + } + + public static final class GpsSatelliteEphemeris.GpsSatelliteClockModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-0.00977F, to=0.00977f) public double getAf0(); + method @FloatRange(from=-3.73E-9F, to=3.73E-9f) public double getAf1(); + method @FloatRange(from=-3.56E-15F, to=3.56E-15f) public double getAf2(); + method @IntRange(from=0, to=1023) public int getIodc(); + method @FloatRange(from=-5.97E-8F, to=5.97E-8f) public double getTgd(); + method @IntRange(from=0) public long getTimeOfClockSeconds(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel> CREATOR; + } + + public static final class GpsSatelliteEphemeris.GpsSatelliteClockModel.Builder { + ctor public GpsSatelliteEphemeris.GpsSatelliteClockModel.Builder(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel build(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel.Builder setAf0(@FloatRange(from=-0.00977F, to=0.00977f) double); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel.Builder setAf1(@FloatRange(from=-3.73E-9F, to=3.73E-9f) double); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel.Builder setAf2(@FloatRange(from=-3.56E-15F, to=3.56E-15f) double); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel.Builder setIodc(@IntRange(from=0, to=1023) int); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel.Builder setTgd(@FloatRange(from=-5.97E-8F, to=5.97E-8f) double); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel.Builder setTimeOfClockSeconds(@IntRange(from=0) long); + } + + public static final class GpsSatelliteEphemeris.GpsSatelliteHealth implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=0.0f) public double getFitInt(); + method @FloatRange(from=0.0f, to=8192.0f) public double getSvAccur(); + method @IntRange(from=0, to=63) public int getSvHealth(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.GpsSatelliteEphemeris.GpsSatelliteHealth> CREATOR; + } + + public static final class GpsSatelliteEphemeris.GpsSatelliteHealth.Builder { + ctor public GpsSatelliteEphemeris.GpsSatelliteHealth.Builder(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteHealth build(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteHealth.Builder setFitInt(@FloatRange(from=0.0f) double); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteHealth.Builder setSvAccur(@FloatRange(from=0.0f, to=8192.0f) double); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteHealth.Builder setSvHealth(@IntRange(from=0, to=63) int); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class IonosphericCorrection implements android.os.Parcelable { + ctor public IonosphericCorrection(@IntRange(from=0) long, @NonNull android.location.GnssCorrectionComponent); + method public int describeContents(); + method @IntRange(from=0) public long getCarrierFrequencyHz(); + method @NonNull public android.location.GnssCorrectionComponent getIonosphericCorrection(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.IonosphericCorrection> CREATOR; + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class KeplerianOrbitModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-1.18E-8F, to=1.18E-8f) public double getDeltaN(); + method @FloatRange(from=0.0f, to=0.5f) public double getEccentricity(); + method @FloatRange(from=-3.15F, to=3.15f) public double getI0(); + method @FloatRange(from=-2.94E-9F, to=2.94E-9f) public double getIDot(); + method @FloatRange(from=-3.15F, to=3.15f) public double getM0(); + method @FloatRange(from=-3.15F, to=3.15f) public double getOmega(); + method @FloatRange(from=-3.15F, to=3.15f) public double getOmega0(); + method @FloatRange(from=-3.1E-6F, to=3.1E-6f) public double getOmegaDot(); + method @FloatRange(from=0.0f, to=8192.0f) public double getRootA(); + method @NonNull public android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation getSecondOrderHarmonicPerturbation(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.KeplerianOrbitModel> CREATOR; + } + + public static final class KeplerianOrbitModel.Builder { + ctor public KeplerianOrbitModel.Builder(); + method @NonNull public android.location.KeplerianOrbitModel build(); + method @NonNull public android.location.KeplerianOrbitModel.Builder setDeltaN(@FloatRange(from=-1.18E-8F, to=1.18E-8f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setEccentricity(@FloatRange(from=0.0f, to=0.5f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setI0(@FloatRange(from=-3.15F, to=3.15f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setIDot(@FloatRange(from=-2.94E-9F, to=2.94E-9f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setM0(@FloatRange(from=-3.15F, to=3.15f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setOmega(@FloatRange(from=-3.15F, to=3.15f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setOmega0(@FloatRange(from=-3.15F, to=3.15f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setOmegaDot(@FloatRange(from=-3.1E-6F, to=3.1E-6f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setRootA(@FloatRange(from=0.0f, to=8192.0f) double); + method @NonNull public android.location.KeplerianOrbitModel.Builder setSecondOrderHarmonicPerturbation(@NonNull android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation); + } + + public static final class KeplerianOrbitModel.SecondOrderHarmonicPerturbation implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-6.11E-5F, to=6.11E-5f) public double getCic(); + method @FloatRange(from=-6.11E-5F, to=6.11E-5f) public double getCis(); + method @FloatRange(from=-2048.0F, to=2048.0f) public double getCrc(); + method @FloatRange(from=-2048.0F, to=2048.0f) public double getCrs(); + method @FloatRange(from=-6.11E-5F, to=6.11E-5f) public double getCuc(); + method @FloatRange(from=-6.11E-5F, to=6.11E-5f) public double getCus(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation> CREATOR; + } + + public static final class KeplerianOrbitModel.SecondOrderHarmonicPerturbation.Builder { + ctor public KeplerianOrbitModel.SecondOrderHarmonicPerturbation.Builder(); + method @NonNull public android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation build(); + method @NonNull public android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation.Builder setCic(@FloatRange(from=-6.11E-5F, to=6.11E-5f) double); + method @NonNull public android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation.Builder setCis(@FloatRange(from=-6.11E-5F, to=6.11E-5f) double); + method @NonNull public android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation.Builder setCrc(@FloatRange(from=-2048.0F, to=2048.0f) double); + method @NonNull public android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation.Builder setCrs(@FloatRange(from=-2048.0F, to=2048.0f) double); + method @NonNull public android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation.Builder setCuc(@FloatRange(from=-6.11E-5F, to=6.11E-5f) double); + method @NonNull public android.location.KeplerianOrbitModel.SecondOrderHarmonicPerturbation.Builder setCus(@FloatRange(from=-6.11E-5F, to=6.11E-5f) double); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class KlobucharIonosphericModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-1.193E-7F, to=1.193E-7f) public double getAlpha0(); + method @FloatRange(from=-9.54E-7F, to=9.54E-7f) public double getAlpha1(); + method @FloatRange(from=-7.63E-6F, to=7.63E-6f) public double getAlpha2(); + method @FloatRange(from=-7.63E-6F, to=7.63E-6f) public double getAlpha3(); + method @FloatRange(from=-262144.0F, to=262144.0f) public double getBeta0(); + method @FloatRange(from=-2097152.0F, to=2097152.0f) public double getBeta1(); + method @FloatRange(from=-8388608.0F, to=8388608.0f) public double getBeta2(); + method @FloatRange(from=-8388608.0F, to=8388608.0f) public double getBeta3(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.KlobucharIonosphericModel> CREATOR; + } + + public static final class KlobucharIonosphericModel.Builder { + ctor public KlobucharIonosphericModel.Builder(); + method @NonNull public android.location.KlobucharIonosphericModel build(); + method @NonNull public android.location.KlobucharIonosphericModel.Builder setAlpha0(@FloatRange(from=-1.193E-7F, to=1.193E-7f) double); + method @NonNull public android.location.KlobucharIonosphericModel.Builder setAlpha1(@FloatRange(from=-9.54E-7F, to=9.54E-7f) double); + method @NonNull public android.location.KlobucharIonosphericModel.Builder setAlpha2(@FloatRange(from=-7.63E-6F, to=7.63E-6f) double); + method @NonNull public android.location.KlobucharIonosphericModel.Builder setAlpha3(@FloatRange(from=-7.63E-6F, to=7.63E-6f) double); + method @NonNull public android.location.KlobucharIonosphericModel.Builder setBeta0(@FloatRange(from=-262144.0F, to=262144.0f) double); + method @NonNull public android.location.KlobucharIonosphericModel.Builder setBeta1(@FloatRange(from=-2097152.0F, to=2097152.0f) double); + method @NonNull public android.location.KlobucharIonosphericModel.Builder setBeta2(@FloatRange(from=-8388608.0F, to=8388608.0f) double); + method @NonNull public android.location.KlobucharIonosphericModel.Builder setBeta3(@FloatRange(from=-8388608.0F, to=8388608.0f) double); + } + public final class LastLocationRequest implements android.os.Parcelable { method public int describeContents(); method public boolean isAdasGnssBypass(); @@ -436,6 +1099,25 @@ package android.location { method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_BYPASS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean); } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class LeapSecondsModel implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0) public int getDayNumberLeapSecondsFuture(); + method @IntRange(from=0) public int getLeapSeconds(); + method @IntRange(from=0) public int getLeapSecondsFuture(); + method @IntRange(from=0) public int getWeekNumberLeapSecondsFuture(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.LeapSecondsModel> CREATOR; + } + + public static final class LeapSecondsModel.Builder { + ctor public LeapSecondsModel.Builder(); + method @NonNull public android.location.LeapSecondsModel build(); + method @NonNull public android.location.LeapSecondsModel.Builder setDayNumberLeapSecondsFuture(@IntRange(from=0) int); + method @NonNull public android.location.LeapSecondsModel.Builder setLeapSeconds(@IntRange(from=0) int); + method @NonNull public android.location.LeapSecondsModel.Builder setLeapSecondsFuture(@IntRange(from=0) int); + method @NonNull public android.location.LeapSecondsModel.Builder setWeekNumberLeapSecondsFuture(@IntRange(from=0) int); + } + public class LocationManager { method @Deprecated @FlaggedApi("android.location.flags.deprecate_provider_request_apis") @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.INTERACT_ACROSS_USERS}) public void addProviderRequestChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.location.provider.ProviderRequest.ChangedListener); method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch(); @@ -513,6 +1195,98 @@ package android.location { method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource); } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class QzssAssistance implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public android.location.GnssAlmanac getAlmanac(); + method @Nullable public android.location.KlobucharIonosphericModel getIonosphericModel(); + method @Nullable public android.location.LeapSecondsModel getLeapSecondsModel(); + method @NonNull public java.util.List<android.location.RealTimeIntegrityModel> getRealTimeIntegrityModels(); + method @NonNull public java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections> getSatelliteCorrections(); + method @NonNull public java.util.List<android.location.QzssSatelliteEphemeris> getSatelliteEphemeris(); + method @NonNull public java.util.List<android.location.TimeModel> getTimeModels(); + method @Nullable public android.location.UtcModel getUtcModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.QzssAssistance> CREATOR; + } + + public static final class QzssAssistance.Builder { + ctor public QzssAssistance.Builder(); + method @NonNull public android.location.QzssAssistance build(); + method @NonNull public android.location.QzssAssistance.Builder setAlmanac(@Nullable android.location.GnssAlmanac); + method @NonNull public android.location.QzssAssistance.Builder setIonosphericModel(@Nullable android.location.KlobucharIonosphericModel); + method @NonNull public android.location.QzssAssistance.Builder setLeapSecondsModel(@Nullable android.location.LeapSecondsModel); + method @NonNull public android.location.QzssAssistance.Builder setRealTimeIntegrityModels(@Nullable java.util.List<android.location.RealTimeIntegrityModel>); + method @NonNull public android.location.QzssAssistance.Builder setSatelliteCorrections(@Nullable java.util.List<android.location.GnssAssistance.GnssSatelliteCorrections>); + method @NonNull public android.location.QzssAssistance.Builder setSatelliteEphemeris(@Nullable java.util.List<android.location.QzssSatelliteEphemeris>); + method @NonNull public android.location.QzssAssistance.Builder setTimeModels(@Nullable java.util.List<android.location.TimeModel>); + method @NonNull public android.location.QzssAssistance.Builder setUtcModel(@Nullable android.location.UtcModel); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class QzssSatelliteEphemeris implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsL2Params getGpsL2Params(); + method @IntRange(from=183, to=206) public int getPrn(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel getSatelliteClockModel(); + method @NonNull public android.location.SatelliteEphemerisTime getSatelliteEphemerisTime(); + method @NonNull public android.location.GpsSatelliteEphemeris.GpsSatelliteHealth getSatelliteHealth(); + method @NonNull public android.location.KeplerianOrbitModel getSatelliteOrbitModel(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.QzssSatelliteEphemeris> CREATOR; + } + + public static final class QzssSatelliteEphemeris.Builder { + ctor public QzssSatelliteEphemeris.Builder(); + method @NonNull public android.location.QzssSatelliteEphemeris build(); + method @NonNull public android.location.QzssSatelliteEphemeris.Builder setGpsL2Params(@NonNull android.location.GpsSatelliteEphemeris.GpsL2Params); + method @NonNull public android.location.QzssSatelliteEphemeris.Builder setPrn(@IntRange(from=183, to=206) int); + method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSatelliteClockModel(@NonNull android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel); + method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSatelliteEphemerisTime(@NonNull android.location.SatelliteEphemerisTime); + method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSatelliteHealth(@NonNull android.location.GpsSatelliteEphemeris.GpsSatelliteHealth); + method @NonNull public android.location.QzssSatelliteEphemeris.Builder setSatelliteOrbitModel(@NonNull android.location.KeplerianOrbitModel); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class RealTimeIntegrityModel implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public String getAdvisoryNumber(); + method @NonNull public String getAdvisoryType(); + method @IntRange(from=0) public long getEndDateSeconds(); + method @IntRange(from=0) public long getPublishDateSeconds(); + method @IntRange(from=0) public long getStartDateSeconds(); + method @IntRange(from=1, to=206) public int getSvid(); + method public boolean isUsable(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.RealTimeIntegrityModel> CREATOR; + } + + public static final class RealTimeIntegrityModel.Builder { + ctor public RealTimeIntegrityModel.Builder(); + method @NonNull public android.location.RealTimeIntegrityModel build(); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setAdvisoryNumber(@NonNull String); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setAdvisoryType(@NonNull String); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setEndDateSeconds(@IntRange(from=0) long); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setPublishDateSeconds(@IntRange(from=0) long); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setStartDateSeconds(@IntRange(from=0) long); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setSvid(@IntRange(from=1, to=206) int); + method @NonNull public android.location.RealTimeIntegrityModel.Builder setUsable(boolean); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class SatelliteEphemerisTime implements android.os.Parcelable { + method public int describeContents(); + method @IntRange(from=0, to=1023) public int getIode(); + method @IntRange(from=0, to=604799) public int getToeSeconds(); + method @IntRange(from=0) public int getWeekNumber(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.SatelliteEphemerisTime> CREATOR; + } + + public static final class SatelliteEphemerisTime.Builder { + ctor public SatelliteEphemerisTime.Builder(); + method @NonNull public android.location.SatelliteEphemerisTime build(); + method @NonNull public android.location.SatelliteEphemerisTime.Builder setIode(@IntRange(from=0, to=1023) int); + method @NonNull public android.location.SatelliteEphemerisTime.Builder setToeSeconds(@IntRange(from=0, to=604799) int); + method @NonNull public android.location.SatelliteEphemerisTime.Builder setWeekNumber(@IntRange(from=0) int); + } + public final class SatellitePvt implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.location.SatellitePvt.ClockInfo getClockInfo(); @@ -587,6 +1361,46 @@ package android.location { field @NonNull public static final android.os.Parcelable.Creator<android.location.SatellitePvt.VelocityEcef> CREATOR; } + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class TimeModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-1.0F, to=1.0f) public double getA0(); + method @FloatRange(from=-3.28E-6F, to=3.28E-6f) public double getA1(); + method @IntRange(from=0, to=604800) public int getTimeOfWeek(); + method public int getToGnss(); + method @IntRange(from=0) public int getWeekNumber(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.TimeModel> CREATOR; + } + + public static final class TimeModel.Builder { + ctor public TimeModel.Builder(); + method @NonNull public android.location.TimeModel build(); + method @NonNull public android.location.TimeModel.Builder setA0(@FloatRange(from=-1.0F, to=1.0f) double); + method @NonNull public android.location.TimeModel.Builder setA1(@FloatRange(from=-3.28E-6F, to=3.28E-6f) double); + method @NonNull public android.location.TimeModel.Builder setTimeOfWeek(@IntRange(from=0, to=604800) int); + method @NonNull public android.location.TimeModel.Builder setToGnss(int); + method @NonNull public android.location.TimeModel.Builder setWeekNumber(@IntRange(from=0) int); + } + + @FlaggedApi("android.location.flags.gnss_assistance_interface") public final class UtcModel implements android.os.Parcelable { + method public int describeContents(); + method @FloatRange(from=-2.0F, to=2.0f) public double getA0(); + method @FloatRange(from=-7.45E-9F, to=7.45E-9f) public double getA1(); + method @IntRange(from=0, to=604800) public int getTimeOfWeek(); + method @IntRange(from=0) public int getWeekNumber(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.location.UtcModel> CREATOR; + } + + public static final class UtcModel.Builder { + ctor public UtcModel.Builder(); + method @NonNull public android.location.UtcModel build(); + method @NonNull public android.location.UtcModel.Builder setA0(@FloatRange(from=-2.0F, to=2.0f) double); + method @NonNull public android.location.UtcModel.Builder setA1(@FloatRange(from=-7.45E-9F, to=7.45E-9f) double); + method @NonNull public android.location.UtcModel.Builder setTimeOfWeek(@IntRange(from=0, to=604800) int); + method @NonNull public android.location.UtcModel.Builder setWeekNumber(@IntRange(from=0) int); + } + } package android.location.provider { diff --git a/location/java/android/location/BeidouAssistance.java b/location/java/android/location/BeidouAssistance.java new file mode 100644 index 000000000000..f55249e605a0 --- /dev/null +++ b/location/java/android/location/BeidouAssistance.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.location.GnssAssistance.GnssSatelliteCorrections; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains Beidou assistance. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class BeidouAssistance implements Parcelable { + + /** The Beidou almanac. */ + @Nullable private final GnssAlmanac mAlmanac; + + /** The Klobuchar ionospheric model. */ + @Nullable private final KlobucharIonosphericModel mIonosphericModel; + + /** The UTC model. */ + @Nullable private final UtcModel mUtcModel; + + /** The leap seconds model. */ + @Nullable private final LeapSecondsModel mLeapSecondsModel; + + /** The list of time models. */ + @NonNull private final List<TimeModel> mTimeModels; + + /** The list of Beidou ephemeris. */ + @NonNull private final List<BeidouSatelliteEphemeris> mSatelliteEphemeris; + + /** The list of real time integrity models. */ + @NonNull private final List<RealTimeIntegrityModel> mRealTimeIntegrityModels; + + /** The list of Beidou satellite corrections. */ + @NonNull private final List<GnssSatelliteCorrections> mSatelliteCorrections; + + private BeidouAssistance(Builder builder) { + mAlmanac = builder.mAlmanac; + mIonosphericModel = builder.mIonosphericModel; + mUtcModel = builder.mUtcModel; + mLeapSecondsModel = builder.mLeapSecondsModel; + if (builder.mTimeModels != null) { + mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); + } else { + mTimeModels = new ArrayList<>(); + } + if (builder.mSatelliteEphemeris != null) { + mSatelliteEphemeris = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteEphemeris)); + } else { + mSatelliteEphemeris = new ArrayList<>(); + } + if (builder.mRealTimeIntegrityModels != null) { + mRealTimeIntegrityModels = + Collections.unmodifiableList(new ArrayList<>(builder.mRealTimeIntegrityModels)); + } else { + mRealTimeIntegrityModels = new ArrayList<>(); + } + if (builder.mSatelliteCorrections != null) { + mSatelliteCorrections = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteCorrections)); + } else { + mSatelliteCorrections = new ArrayList<>(); + } + } + + /** Returns the Beidou almanac. */ + @Nullable + public GnssAlmanac getAlmanac() { + return mAlmanac; + } + + /** Returns the Klobuchar ionospheric model. */ + @Nullable + public KlobucharIonosphericModel getIonosphericModel() { + return mIonosphericModel; + } + + /** Returns the UTC model. */ + @Nullable + public UtcModel getUtcModel() { + return mUtcModel; + } + + /** Returns the leap seconds model. */ + @Nullable + public LeapSecondsModel getLeapSecondsModel() { + return mLeapSecondsModel; + } + + /** Returns the list of time models. */ + @NonNull + public List<TimeModel> getTimeModels() { + return mTimeModels; + } + + /** Returns the list ofBeidou ephemeris. */ + @NonNull + public List<BeidouSatelliteEphemeris> getSatelliteEphemeris() { + return mSatelliteEphemeris; + } + + /** Returns the list of real time integrity models. */ + @NonNull + public List<RealTimeIntegrityModel> getRealTimeIntegrityModels() { + return mRealTimeIntegrityModels; + } + + /** Returns the list of Beidou satellite corrections. */ + @NonNull + public List<GnssSatelliteCorrections> getSatelliteCorrections() { + return mSatelliteCorrections; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("BeidouAssistance["); + builder.append("almanac = ").append(mAlmanac); + builder.append(", ionosphericModel = ").append(mIonosphericModel); + builder.append(", utcModel = ").append(mUtcModel); + builder.append(", leapSecondsModel = ").append(mLeapSecondsModel); + builder.append(", timeModels = ").append(mTimeModels); + builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); + builder.append(", realTimeIntegrityModels = ").append(mRealTimeIntegrityModels); + builder.append(", satelliteCorrections = ").append(mSatelliteCorrections); + builder.append("]"); + return builder.toString(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mAlmanac, flags); + dest.writeTypedObject(mIonosphericModel, flags); + dest.writeTypedObject(mUtcModel, flags); + dest.writeTypedObject(mLeapSecondsModel, flags); + dest.writeTypedList(mTimeModels); + dest.writeTypedList(mSatelliteEphemeris); + dest.writeTypedList(mRealTimeIntegrityModels); + dest.writeTypedList(mSatelliteCorrections); + } + + public static final @android.annotation.NonNull Creator<BeidouAssistance> CREATOR = + new Creator<BeidouAssistance>() { + @Override + public BeidouAssistance createFromParcel(Parcel in) { + return new BeidouAssistance.Builder() + .setAlmanac(in.readTypedObject(GnssAlmanac.CREATOR)) + .setIonosphericModel( + in.readTypedObject(KlobucharIonosphericModel.CREATOR)) + .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) + .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) + .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) + .setSatelliteEphemeris( + in.createTypedArrayList(BeidouSatelliteEphemeris.CREATOR)) + .setRealTimeIntegrityModels( + in.createTypedArrayList(RealTimeIntegrityModel.CREATOR)) + .setSatelliteCorrections( + in.createTypedArrayList(GnssSatelliteCorrections.CREATOR)) + .build(); + } + + @Override + public BeidouAssistance[] newArray(int size) { + return new BeidouAssistance[size]; + } + }; + + /** Builder for {@link BeidouAssistance}. */ + public static final class Builder { + private GnssAlmanac mAlmanac; + private KlobucharIonosphericModel mIonosphericModel; + private UtcModel mUtcModel; + private LeapSecondsModel mLeapSecondsModel; + private List<TimeModel> mTimeModels; + private List<BeidouSatelliteEphemeris> mSatelliteEphemeris; + private List<RealTimeIntegrityModel> mRealTimeIntegrityModels; + private List<GnssSatelliteCorrections> mSatelliteCorrections; + + /** Sets the Beidou almanac. */ + @NonNull + public Builder setAlmanac(@Nullable GnssAlmanac almanac) { + mAlmanac = almanac; + return this; + } + + /** Sets the Klobuchar ionospheric model. */ + @NonNull + public Builder setIonosphericModel(@Nullable KlobucharIonosphericModel ionosphericModel) { + mIonosphericModel = ionosphericModel; + return this; + } + + /** Sets the UTC model. */ + @NonNull + public Builder setUtcModel(@Nullable UtcModel utcModel) { + mUtcModel = utcModel; + return this; + } + + /** Sets the leap seconds model. */ + @NonNull + public Builder setLeapSecondsModel(@Nullable LeapSecondsModel leapSecondsModel) { + mLeapSecondsModel = leapSecondsModel; + return this; + } + + /** Sets the list of time models. */ + @NonNull + public Builder setTimeModels( + @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + mTimeModels = timeModels; + return this; + } + + /** Sets the list of Beidou ephemeris. */ + @NonNull + public Builder setSatelliteEphemeris( + @Nullable @SuppressLint("NullableCollection") + List<BeidouSatelliteEphemeris> satelliteEphemeris) { + mSatelliteEphemeris = satelliteEphemeris; + return this; + } + + /** Sets the list of real time integrity models. */ + @NonNull + public Builder setRealTimeIntegrityModels( + @Nullable @SuppressLint("NullableCollection") + List<RealTimeIntegrityModel> realTimeIntegrityModels) { + mRealTimeIntegrityModels = realTimeIntegrityModels; + return this; + } + + /** Sets the list of Beidou satellite corrections. */ + @NonNull + public Builder setSatelliteCorrections( + @Nullable @SuppressLint("NullableCollection") + List<GnssSatelliteCorrections> satelliteCorrections) { + mSatelliteCorrections = satelliteCorrections; + return this; + } + + /** Builds the {@link BeidouAssistance}. */ + @NonNull + public BeidouAssistance build() { + return new BeidouAssistance(this); + } + } +} diff --git a/location/java/android/location/BeidouSatelliteEphemeris.java b/location/java/android/location/BeidouSatelliteEphemeris.java new file mode 100644 index 000000000000..6bd91e3318c3 --- /dev/null +++ b/location/java/android/location/BeidouSatelliteEphemeris.java @@ -0,0 +1,647 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains ephemeris parameters specific to Beidou satellites. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class BeidouSatelliteEphemeris implements Parcelable { + /** The PRN number of the Beidou satellite. */ + private final int mPrn; + + /** Satellite clock model. */ + private final BeidouSatelliteClockModel mSatelliteClockModel; + + /** Satellite orbit model. */ + private final KeplerianOrbitModel mSatelliteOrbitModel; + + /** Satellite health. */ + private final BeidouSatelliteHealth mSatelliteHealth; + + /** Satellite ephemeris time. */ + private final BeidouSatelliteEphemerisTime mSatelliteEphemerisTime; + + private BeidouSatelliteEphemeris(Builder builder) { + // Allow PRN beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mPrn >= 1); + Preconditions.checkNotNull(builder.mSatelliteClockModel, + "SatelliteClockModel cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteOrbitModel, + "SatelliteOrbitModel cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteHealth, + "SatelliteHealth cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteEphemerisTime, + "SatelliteEphemerisTime cannot be null"); + mPrn = builder.mPrn; + mSatelliteClockModel = builder.mSatelliteClockModel; + mSatelliteOrbitModel = builder.mSatelliteOrbitModel; + mSatelliteHealth = builder.mSatelliteHealth; + mSatelliteEphemerisTime = builder.mSatelliteEphemerisTime; + } + + /** Returns the PRN of the satellite. */ + @IntRange(from = 1, to = 63) + public int getPrn() { + return mPrn; + } + + /** Returns the satellite clock model. */ + @NonNull + public BeidouSatelliteClockModel getSatelliteClockModel() { + return mSatelliteClockModel; + } + + /** Returns the satellite orbit model. */ + @NonNull + public KeplerianOrbitModel getSatelliteOrbitModel() { + return mSatelliteOrbitModel; + } + + /** Returns the satellite health. */ + @NonNull + public BeidouSatelliteHealth getSatelliteHealth() { + return mSatelliteHealth; + } + + /** Returns the satellite ephemeris time. */ + @NonNull + public BeidouSatelliteEphemerisTime getSatelliteEphemerisTime() { + return mSatelliteEphemerisTime; + } + + public static final @NonNull Creator<BeidouSatelliteEphemeris> CREATOR = + new Creator<BeidouSatelliteEphemeris>() { + @Override + @NonNull + public BeidouSatelliteEphemeris createFromParcel(Parcel in) { + final BeidouSatelliteEphemeris.Builder beidouSatelliteEphemeris = + new Builder() + .setPrn(in.readInt()) + .setSatelliteClockModel( + in.readTypedObject(BeidouSatelliteClockModel.CREATOR)) + .setSatelliteOrbitModel( + in.readTypedObject(KeplerianOrbitModel.CREATOR)) + .setSatelliteHealth( + in.readTypedObject(BeidouSatelliteHealth.CREATOR)) + .setSatelliteEphemerisTime( + in.readTypedObject( + BeidouSatelliteEphemerisTime.CREATOR)); + return beidouSatelliteEphemeris.build(); + } + + @Override + public BeidouSatelliteEphemeris[] newArray(int size) { + return new BeidouSatelliteEphemeris[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mPrn); + parcel.writeTypedObject(mSatelliteClockModel, flags); + parcel.writeTypedObject(mSatelliteOrbitModel, flags); + parcel.writeTypedObject(mSatelliteHealth, flags); + parcel.writeTypedObject(mSatelliteEphemerisTime, flags); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("BeidouSatelliteEphemeris["); + builder.append("prn = ").append(mPrn); + builder.append(", satelliteClockModel = ").append(mSatelliteClockModel); + builder.append(", satelliteOrbitModel = ").append(mSatelliteOrbitModel); + builder.append(", satelliteHealth = ").append(mSatelliteHealth); + builder.append(", satelliteEphemerisTime = ").append(mSatelliteEphemerisTime); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link BeidouSatelliteEphemeris} */ + public static final class Builder { + private int mPrn; + private BeidouSatelliteClockModel mSatelliteClockModel; + private KeplerianOrbitModel mSatelliteOrbitModel; + private BeidouSatelliteHealth mSatelliteHealth; + private BeidouSatelliteEphemerisTime mSatelliteEphemerisTime; + + /** Sets the PRN of the satellite. */ + @NonNull + public Builder setPrn(int prn) { + mPrn = prn; + return this; + } + + /** Sets the satellite clock model. */ + @NonNull + public Builder setSatelliteClockModel( + @NonNull BeidouSatelliteClockModel satelliteClockModel) { + mSatelliteClockModel = satelliteClockModel; + return this; + } + + /** Sets the satellite orbit model. */ + @NonNull + public Builder setSatelliteOrbitModel(@NonNull KeplerianOrbitModel satelliteOrbitModel) { + mSatelliteOrbitModel = satelliteOrbitModel; + return this; + } + + /** Sets the satellite health. */ + @NonNull + public Builder setSatelliteHealth(@NonNull BeidouSatelliteHealth satelliteHealth) { + mSatelliteHealth = satelliteHealth; + return this; + } + + /** Sets the satellite ephemeris time. */ + @NonNull + public Builder setSatelliteEphemerisTime( + @NonNull BeidouSatelliteEphemerisTime satelliteEphemerisTime) { + mSatelliteEphemerisTime = satelliteEphemerisTime; + return this; + } + + /** Builds a {@link BeidouSatelliteEphemeris} instance as specified by this builder. */ + @NonNull + public BeidouSatelliteEphemeris build() { + return new BeidouSatelliteEphemeris(this); + } + } + + /** + * A class contains the set of parameters needed for Beidou satellite clock correction. + * + * <p>This is defined in BDS-SIS-ICD-B1I-3.0, section 5.2.4.9, 5.2.4.10. + */ + public static final class BeidouSatelliteClockModel implements Parcelable { + /** + * Time of the clock in seconds since Beidou epoch. + * + * <p>Corresponds to the 'Epoch' field within the 'SV/EPOCH/SV CLK' record of Beidou + * navigation message in RINEX 3.05 Table A14. + */ + private final long mTimeOfClockSeconds; + + /** SV clock bias in seconds. */ + private final double mAf0; + + /** SV clock drift in seconds per second. */ + private final double mAf1; + + /** SV clock drift in seconds per second squared. */ + private final double mAf2; + + /** Group delay differential 1 B1/B3 in seconds. */ + private final double mTgd1; + + /** Group delay differential 2 B2/B3 in seconds. */ + private final double mTgd2; + + /** + * Age of Data Clock. + * <p>This is defined in BDS-SIS-ICD-B1I-3.0 Section 5.2.4.8 Table 5-6. + */ + private final int mAodc; + + private BeidouSatelliteClockModel(Builder builder) { + Preconditions.checkArgument(builder.mTimeOfClockSeconds >= 0); + Preconditions.checkArgumentInRange(builder.mAf0, -9.77e-3f, 9.77e-3f, "Af0"); + Preconditions.checkArgumentInRange(builder.mAf1, -1.87e-9f, 1.87e-9f, "Af1"); + Preconditions.checkArgumentInRange(builder.mAf2, -1.39e-17f, 1.39e-17f, "Af2"); + Preconditions.checkArgumentInRange(builder.mTgd1, -5.12e-8f, 5.12e-8f, "Tgd1"); + Preconditions.checkArgumentInRange(builder.mTgd2, -5.12e-8f, 5.12e-8f, "Tgd2"); + Preconditions.checkArgumentInRange(builder.mAodc, 0, 31, "Aodc"); + mTimeOfClockSeconds = builder.mTimeOfClockSeconds; + mAf0 = builder.mAf0; + mAf1 = builder.mAf1; + mAf2 = builder.mAf2; + mTgd1 = builder.mTgd1; + mTgd2 = builder.mTgd2; + mAodc = builder.mAodc; + } + + /** Returns the time of the clock in seconds since Beidou epoch. */ + @IntRange(from = 0) + public long getTimeOfClockSeconds() { + return mTimeOfClockSeconds; + } + + /** Returns the SV clock bias in seconds. */ + @FloatRange(from = -9.77e-3f, to = 9.77e-3f) + public double getAf0() { + return mAf0; + } + + /** Returns the SV clock drift in seconds per second. */ + @FloatRange(from = -1.87e-9f, to = 1.87e-9f) + public double getAf1() { + return mAf1; + } + + /** Returns the SV clock drift in seconds per second squared. */ + @FloatRange(from = -1.39e-17f, to = 1.39e-17f) + public double getAf2() { + return mAf2; + } + + /** Returns the group delay differential 1 B1/B3 in seconds. */ + @FloatRange(from = -5.12e-8f, to = 5.12e-8f) + public double getTgd1() { + return mTgd1; + } + + /** Returns the group delay differential 2 B2/B3 in seconds. */ + @FloatRange(from = -5.12e-8f, to = 5.12e-8f) + public double getTgd2() { + return mTgd2; + } + + /** Returns the age of data clock. */ + @IntRange(from = 0, to = 31) + public int getAodc() { + return mAodc; + } + + public static final @NonNull Creator<BeidouSatelliteClockModel> CREATOR = + new Creator<BeidouSatelliteClockModel>() { + @Override + @NonNull + public BeidouSatelliteClockModel createFromParcel(Parcel in) { + final BeidouSatelliteClockModel.Builder beidouSatelliteClockModel = + new Builder() + .setTimeOfClockSeconds(in.readLong()) + .setAf0(in.readDouble()) + .setAf1(in.readDouble()) + .setAf2(in.readDouble()) + .setTgd1(in.readDouble()) + .setTgd2(in.readDouble()) + .setAodc(in.readInt()); + return beidouSatelliteClockModel.build(); + } + + @Override + public BeidouSatelliteClockModel[] newArray(int size) { + return new BeidouSatelliteClockModel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeLong(mTimeOfClockSeconds); + parcel.writeDouble(mAf0); + parcel.writeDouble(mAf1); + parcel.writeDouble(mAf2); + parcel.writeDouble(mTgd1); + parcel.writeDouble(mTgd2); + parcel.writeInt(mAodc); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("BeidouSatelliteClockModel["); + builder.append("timeOfClockSeonds = ").append(mTimeOfClockSeconds); + builder.append(", af0 = ").append(mAf0); + builder.append(", af1 = ").append(mAf1); + builder.append(", af2 = ").append(mAf2); + builder.append(", tgd1 = ").append(mTgd1); + builder.append(", tgd2 = ").append(mTgd2); + builder.append(", aodc = ").append(mAodc); + return builder.toString(); + } + + /** Builder for {@link BeidouSatelliteClockModel} */ + public static final class Builder { + private long mTimeOfClockSeconds; + private double mAf0; + private double mAf1; + private double mAf2; + private double mTgd1; + private double mTgd2; + private int mAodc; + + /** Sets the time of the clock in seconds since Beidou epoch. */ + @NonNull + public Builder setTimeOfClockSeconds(@IntRange(from = 0) long timeOfClockSeconds) { + mTimeOfClockSeconds = timeOfClockSeconds; + return this; + } + + /** Sets the SV clock bias in seconds. */ + @NonNull + public Builder setAf0(@FloatRange(from = -9.77e-3f, to = 9.77e-3f)double af0) { + mAf0 = af0; + return this; + } + + /** Sets the SV clock drift in seconds per second. */ + @NonNull + public Builder setAf1(@FloatRange(from = -1.87e-9f, to = 1.87e-9f) double af1) { + mAf1 = af1; + return this; + } + + /** Sets the SV clock drift in seconds per second squared. */ + @NonNull + public Builder setAf2(@FloatRange(from = -1.39e-17f, to = 1.39e-17f) double af2) { + mAf2 = af2; + return this; + } + + /** Sets the group delay differential 1 B1/B3 in seconds. */ + @NonNull + public Builder setTgd1(@FloatRange(from = -5.12e-8f, to = 5.12e-8f) double tgd1) { + mTgd1 = tgd1; + return this; + } + + /** Sets the group delay differential 2 B2/B3 in seconds. */ + @NonNull + public Builder setTgd2(@FloatRange(from = -5.12e-8f, to = 5.12e-8f) double tgd2) { + mTgd2 = tgd2; + return this; + } + + /** Sets the age of data clock. */ + @NonNull + public Builder setAodc(@IntRange(from = 0, to = 31) int aodc) { + mAodc = aodc; + return this; + } + + /** Builds a {@link BeidouSatelliteClockModel} instance as specified by this builder. */ + @NonNull + public BeidouSatelliteClockModel build() { + return new BeidouSatelliteClockModel(this); + } + } + } + + /** A class contains Beidou satellite health. */ + public static final class BeidouSatelliteHealth implements Parcelable { + /** + * The autonomous satellite health flag (SatH1) occupies 1 bit. + * + * <p>“0” means broadcasting satellite is good and “1” means not. + * + * <p>This is defined in BDS-SIS-ICD-B1I-3.0 section 5.2.4.6. + */ + private final int mSatH1; + + /** + * SV accuracy in meters. + * + * <p>This is defined in the "BROADCAST ORBIT - 6" record of RINEX 3.05 + * Table A14, pp.78. + */ + private final double mSvAccur; + + private BeidouSatelliteHealth(Builder builder) { + // Allow SatH1 beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSatH1 >= 0); + Preconditions.checkArgumentInRange(builder.mSvAccur, 0.0f, 8192.0f, "SvAccur"); + mSatH1 = builder.mSatH1; + mSvAccur = builder.mSvAccur; + } + + /** Returns the autonomous satellite health flag (SatH1) */ + @IntRange(from = 0, to = 1) + public int getSatH1() { + return mSatH1; + } + + /** Returns the SV accuracy in meters. */ + @FloatRange(from = 0.0f, to = 8192.0f) + public double getSvAccur() { + return mSvAccur; + } + + public static final @NonNull Creator<BeidouSatelliteHealth> CREATOR = + new Creator<BeidouSatelliteHealth>() { + @Override + @NonNull + public BeidouSatelliteHealth createFromParcel(Parcel in) { + final BeidouSatelliteHealth.Builder beidouSatelliteHealth = + new Builder().setSatH1(in.readInt()).setSvAccur(in.readDouble()); + return beidouSatelliteHealth.build(); + } + + @Override + public BeidouSatelliteHealth[] newArray(int size) { + return new BeidouSatelliteHealth[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mSatH1); + parcel.writeDouble(mSvAccur); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("BeidouSatelliteHealth["); + builder.append("satH1 = ").append(mSatH1); + builder.append(", svAccur = ").append(mSvAccur); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link BeidouSatelliteHealth} */ + public static final class Builder { + private int mSatH1; + private double mSvAccur; + + /** Sets the autonomous satellite health flag (SatH1) */ + @NonNull + public Builder setSatH1(int satH1) { + mSatH1 = satH1; + return this; + } + + /** Sets the SV accuracy in meters. */ + @NonNull + public Builder setSvAccur(double svAccur) { + mSvAccur = svAccur; + return this; + } + + /** Builds a {@link BeidouSatelliteHealth} instance as specified by this builder. */ + @NonNull + public BeidouSatelliteHealth build() { + return new BeidouSatelliteHealth(this); + } + } + } + + /** A class contains Beidou satellite ephemeris time. */ + public static final class BeidouSatelliteEphemerisTime implements Parcelable { + /** + * AODE Age of Data, Ephemeris. + * + * <p>This is defined in BDS-SIS-ICD-B1I-3.0 section 5.2.4.11 Table 5-8. + */ + private final int mIode; + + /** Beidou week number without rollover */ + private final int mBeidouWeekNumber; + + /** + * Time of ephemeris in seconds. + * + * <p>This is defined in BDS-SIS-ICD-B1I-3.0 section 5.2.4.12. + */ + private final int mToeSeconds; + + private BeidouSatelliteEphemerisTime(Builder builder) { + Preconditions.checkArgumentInRange(builder.mIode, 0, 31, "Iode"); + Preconditions.checkArgument(builder.mBeidouWeekNumber >= 0); + Preconditions.checkArgumentInRange(builder.mToeSeconds, 0, 604792, "ToeSeconds"); + mIode = builder.mIode; + mBeidouWeekNumber = builder.mBeidouWeekNumber; + mToeSeconds = builder.mToeSeconds; + } + + /** Returns the AODE Age of Data, Ephemeris. */ + @IntRange(from = 0, to = 31) + public int getIode() { + return mIode; + } + + /** Returns the Beidou week number without rollover . */ + @IntRange(from = 0) + public int getBeidouWeekNumber() { + return mBeidouWeekNumber; + } + + /** Returns the time of ephemeris in seconds. */ + @IntRange(from = 0, to = 604792) + public int getToeSeconds() { + return mToeSeconds; + } + + public static final @NonNull Creator<BeidouSatelliteEphemerisTime> CREATOR = + new Creator<BeidouSatelliteEphemerisTime>() { + @Override + @NonNull + public BeidouSatelliteEphemerisTime createFromParcel(Parcel in) { + final BeidouSatelliteEphemerisTime.Builder beidouSatelliteEphemerisTime = + new Builder() + .setIode(in.readInt()) + .setBeidouWeekNumber(in.readInt()) + .setToeSeconds(in.readInt()); + return beidouSatelliteEphemerisTime.build(); + } + + @Override + public BeidouSatelliteEphemerisTime[] newArray(int size) { + return new BeidouSatelliteEphemerisTime[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mIode); + parcel.writeInt(mBeidouWeekNumber); + parcel.writeInt(mToeSeconds); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("BeidouSatelliteEphemerisTime["); + builder.append("iode = ").append(mIode); + builder.append(", beidouWeekNumber = ").append(mBeidouWeekNumber); + builder.append(", toeSeconds = ").append(mToeSeconds); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link BeidouSatelliteEphemerisTime} */ + public static final class Builder { + private int mIode; + private int mBeidouWeekNumber; + private int mToeSeconds; + + /** Sets the AODE Age of Data, Ephemeris. */ + @NonNull + public Builder setIode(int iode) { + mIode = iode; + return this; + } + + /** Sets the Beidou week number without rollover */ + @NonNull + public Builder setBeidouWeekNumber( + @IntRange(from = 0) int beidouWeekNumber) { + mBeidouWeekNumber = beidouWeekNumber; + return this; + } + + /** Sets the time of ephemeris in seconds. */ + @NonNull + public Builder setToeSeconds(@IntRange(from = 0, to = 604792) int toeSeconds) { + mToeSeconds = toeSeconds; + return this; + } + + /** + * Builds a {@link BeidouSatelliteEphemerisTime} instance as specified by this builder. + */ + @NonNull + public BeidouSatelliteEphemerisTime build() { + return new BeidouSatelliteEphemerisTime(this); + } + } + } +} diff --git a/location/java/android/location/GalileoAssistance.java b/location/java/android/location/GalileoAssistance.java new file mode 100644 index 000000000000..07c5bab856db --- /dev/null +++ b/location/java/android/location/GalileoAssistance.java @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.location.GnssAssistance.GnssSatelliteCorrections; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains Galileo assistance. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GalileoAssistance implements Parcelable { + + /** The Galileo almanac. */ + @Nullable private final GnssAlmanac mAlmanac; + + /** The Klobuchar ionospheric model. */ + @Nullable private final KlobucharIonosphericModel mIonosphericModel; + + /** The UTC model. */ + @Nullable private final UtcModel mUtcModel; + + /** The leap seconds model. */ + @Nullable private final LeapSecondsModel mLeapSecondsModel; + + /** The list of time models. */ + @NonNull private final List<TimeModel> mTimeModels; + + /** The list of Galileo ephemeris. */ + @NonNull private final List<GalileoSatelliteEphemeris> mSatelliteEphemeris; + + /** The list of real time integrity models. */ + @NonNull private final List<RealTimeIntegrityModel> mRealTimeIntegrityModels; + + /** The list of Galileo satellite corrections. */ + @NonNull private final List<GnssSatelliteCorrections> mSatelliteCorrections; + + private GalileoAssistance(Builder builder) { + mAlmanac = builder.mAlmanac; + mIonosphericModel = builder.mIonosphericModel; + mUtcModel = builder.mUtcModel; + mLeapSecondsModel = builder.mLeapSecondsModel; + if (builder.mTimeModels != null) { + mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); + } else { + mTimeModels = new ArrayList<>(); + } + if (builder.mSatelliteEphemeris != null) { + mSatelliteEphemeris = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteEphemeris)); + } else { + mSatelliteEphemeris = new ArrayList<>(); + } + if (builder.mRealTimeIntegrityModels != null) { + mRealTimeIntegrityModels = + Collections.unmodifiableList(new ArrayList<>(builder.mRealTimeIntegrityModels)); + } else { + mRealTimeIntegrityModels = new ArrayList<>(); + } + if (builder.mSatelliteCorrections != null) { + mSatelliteCorrections = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteCorrections)); + } else { + mSatelliteCorrections = new ArrayList<>(); + } + } + + /** Returns the Galileo almanac. */ + @Nullable + public GnssAlmanac getAlmanac() { + return mAlmanac; + } + + /** Returns the Klobuchar ionospheric model. */ + @Nullable + public KlobucharIonosphericModel getIonosphericModel() { + return mIonosphericModel; + } + + /** Returns the UTC model. */ + @Nullable + public UtcModel getUtcModel() { + return mUtcModel; + } + + /** Returns the leap seconds model. */ + @Nullable + public LeapSecondsModel getLeapSecondsModel() { + return mLeapSecondsModel; + } + + /** Returns the list of time models. */ + @NonNull + public List<TimeModel> getTimeModels() { + return mTimeModels; + } + + /** Returns the list of Galileo ephemeris. */ + @NonNull + public List<GalileoSatelliteEphemeris> getSatelliteEphemeris() { + return mSatelliteEphemeris; + } + + /** Returns the list of real time integrity models. */ + @NonNull + public List<RealTimeIntegrityModel> getRealTimeIntegrityModels() { + return mRealTimeIntegrityModels; + } + + /** Returns the list of Galileo satellite corrections. */ + @NonNull + public List<GnssSatelliteCorrections> getSatelliteCorrections() { + return mSatelliteCorrections; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mAlmanac, flags); + dest.writeTypedObject(mIonosphericModel, flags); + dest.writeTypedObject(mUtcModel, flags); + dest.writeTypedObject(mLeapSecondsModel, flags); + dest.writeTypedList(mTimeModels); + dest.writeTypedList(mSatelliteEphemeris); + dest.writeTypedList(mRealTimeIntegrityModels); + dest.writeTypedList(mSatelliteCorrections); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GalileoAssistance["); + builder.append("almanac = ").append(mAlmanac); + builder.append(", ionosphericModel = ").append(mIonosphericModel); + builder.append(", utcModel = ").append(mUtcModel); + builder.append(", leapSecondsModel = ").append(mLeapSecondsModel); + builder.append(", timeModels = ").append(mTimeModels); + builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); + builder.append(", realTimeIntegrityModels = ").append(mRealTimeIntegrityModels); + builder.append(", satelliteCorrections = ").append(mSatelliteCorrections); + builder.append("]"); + return builder.toString(); + } + + public static final @android.annotation.NonNull Creator<GalileoAssistance> CREATOR = + new Creator<GalileoAssistance>() { + @Override + public GalileoAssistance createFromParcel(Parcel in) { + return new GalileoAssistance.Builder() + .setAlmanac(in.readTypedObject(GnssAlmanac.CREATOR)) + .setIonosphericModel( + in.readTypedObject(KlobucharIonosphericModel.CREATOR)) + .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) + .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) + .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) + .setSatelliteEphemeris( + in.createTypedArrayList(GalileoSatelliteEphemeris.CREATOR)) + .setRealTimeIntegrityModels( + in.createTypedArrayList(RealTimeIntegrityModel.CREATOR)) + .setSatelliteCorrections( + in.createTypedArrayList(GnssSatelliteCorrections.CREATOR)) + .build(); + } + + @Override + public GalileoAssistance[] newArray(int size) { + return new GalileoAssistance[size]; + } + }; + + /** Builder for {@link GalileoAssistance}. */ + public static final class Builder { + private GnssAlmanac mAlmanac; + private KlobucharIonosphericModel mIonosphericModel; + private UtcModel mUtcModel; + private LeapSecondsModel mLeapSecondsModel; + private List<TimeModel> mTimeModels; + private List<GalileoSatelliteEphemeris> mSatelliteEphemeris; + private List<RealTimeIntegrityModel> mRealTimeIntegrityModels; + private List<GnssSatelliteCorrections> mSatelliteCorrections; + + /** Sets the Galileo almanac. */ + @NonNull + public Builder setAlmanac(@Nullable GnssAlmanac almanac) { + mAlmanac = almanac; + return this; + } + + /** Sets the Klobuchar ionospheric model. */ + @NonNull + public Builder setIonosphericModel(@Nullable KlobucharIonosphericModel ionosphericModel) { + mIonosphericModel = ionosphericModel; + return this; + } + + /** Sets the UTC model. */ + @NonNull + public Builder setUtcModel(@Nullable UtcModel utcModel) { + mUtcModel = utcModel; + return this; + } + + /** Sets the leap seconds model. */ + @NonNull + public Builder setLeapSecondsModel(@Nullable LeapSecondsModel leapSecondsModel) { + mLeapSecondsModel = leapSecondsModel; + return this; + } + + /** Sets the list of time models. */ + @NonNull + public Builder setTimeModels( + @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + mTimeModels = timeModels; + return this; + } + + /** Sets the list of Galileo ephemeris. */ + @NonNull + public Builder setSatelliteEphemeris( + @Nullable @SuppressLint("NullableCollection") + List<GalileoSatelliteEphemeris> satelliteEphemeris) { + mSatelliteEphemeris = satelliteEphemeris; + return this; + } + + /** Sets the list of real time integrity models. */ + @NonNull + public Builder setRealTimeIntegrityModels( + @Nullable @SuppressLint("NullableCollection") + List<RealTimeIntegrityModel> realTimeIntegrityModels) { + mRealTimeIntegrityModels = realTimeIntegrityModels; + return this; + } + + /** Sets the list of Galileo satellite corrections. */ + @NonNull + public Builder setSatelliteCorrections( + @Nullable @SuppressLint("NullableCollection") + List<GnssSatelliteCorrections> satelliteCorrections) { + mSatelliteCorrections = satelliteCorrections; + return this; + } + + /** Builds the {@link GalileoAssistance}. */ + @NonNull + public GalileoAssistance build() { + return new GalileoAssistance(this); + } + } +} diff --git a/location/java/android/location/GalileoIonosphericModel.java b/location/java/android/location/GalileoIonosphericModel.java new file mode 100644 index 000000000000..6638be9af2b6 --- /dev/null +++ b/location/java/android/location/GalileoIonosphericModel.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * Contains Galileo ionospheric model. + * + * <p>This is defined in Galileo-OS-SIS-ICD-v2.1, section 5.1.6. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GalileoIonosphericModel implements Parcelable { + /** Effective ionisation level 1st order parameter in sfu. */ + private final double mAi0; + + /** Effective ionisation level 2nd order parameter in sfu per degree. */ + private final double mAi1; + + /** Effective ionisation level 3nd order parameter in sfu per degree squared. */ + private final double mAi2; + + private GalileoIonosphericModel(Builder builder) { + Preconditions.checkArgumentInRange(builder.mAi0, 0.0f, 512.0f, "Ai0"); + Preconditions.checkArgumentInRange(builder.mAi1, -4.0f, 4.0f, "Ai1"); + Preconditions.checkArgumentInRange(builder.mAi2, -0.5f, 0.5f, "Ai2"); + mAi0 = builder.mAi0; + mAi1 = builder.mAi1; + mAi2 = builder.mAi2; + } + + /** Returns the effective ionisation level 1st order parameter in sfu. */ + @FloatRange(from = 0.0f, to = 512.0f) + public double getAi0() { + return mAi0; + } + + /** Returns the effective ionisation level 2nd order parameter in sfu per degree. */ + @FloatRange(from = -4.0f, to = 4.0f) + public double getAi1() { + return mAi1; + } + + /** Returns the effective ionisation level 3nd order parameter in sfu per degree squared. */ + @FloatRange(from = -0.5f, to = 0.5f) + public double getAi2() { + return mAi2; + } + + public static final @NonNull Parcelable.Creator<GalileoIonosphericModel> CREATOR = + new Parcelable.Creator<GalileoIonosphericModel>() { + @Override + public GalileoIonosphericModel createFromParcel(@NonNull Parcel source) { + return new GalileoIonosphericModel.Builder() + .setAi0(source.readDouble()) + .setAi1(source.readDouble()) + .setAi2(source.readDouble()) + .build(); + } + + @Override + public GalileoIonosphericModel[] newArray(int size) { + return new GalileoIonosphericModel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeDouble(mAi0); + dest.writeDouble(mAi1); + dest.writeDouble(mAi2); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GalileoIonosphericModel["); + builder.append("ai0 = ").append(mAi0); + builder.append(", ai1 = ").append(mAi1); + builder.append(", ai2 = ").append(mAi2); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GalileoIonosphericModel}. */ + public static final class Builder { + private double mAi0; + private double mAi1; + private double mAi2; + + /** Sets the effective ionisation level 1st order parameter in sfu. */ + @NonNull + public Builder setAi0(@FloatRange(from = 0.0f, to = 512.0f) double ai0) { + mAi0 = ai0; + return this; + } + + /** Sets the effective ionisation level 2nd order parameter in sfu per degree. */ + @NonNull + public Builder setAi1(@FloatRange(from = -4.0f, to = 4.0f) double ai1) { + mAi1 = ai1; + return this; + } + + /** Sets the effective ionisation level 3nd order parameter in sfu per degree squared. */ + @NonNull + public Builder setAi2(@FloatRange(from = -0.5f, to = 0.5f) double ai2) { + mAi2 = ai2; + return this; + } + + /** Builds a {@link GalileoIonosphericModel}. */ + @NonNull + public GalileoIonosphericModel build() { + return new GalileoIonosphericModel(this); + } + } +} diff --git a/location/java/android/location/GalileoSatelliteEphemeris.java b/location/java/android/location/GalileoSatelliteEphemeris.java new file mode 100644 index 000000000000..7dd371176267 --- /dev/null +++ b/location/java/android/location/GalileoSatelliteEphemeris.java @@ -0,0 +1,660 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Contains ephemeris parameters specific to Galileo satellites. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GalileoSatelliteEphemeris implements Parcelable { + + /** Satellite code number. */ + private int mSatelliteCodeNumber; + + /** Array of satellite clock model. */ + @NonNull private final List<GalileoSatelliteClockModel> mSatelliteClockModels; + + /** Satellite orbit model. */ + @NonNull private final KeplerianOrbitModel mSatelliteOrbitModel; + + /** Satellite health. */ + @NonNull private final GalileoSvHealth mSatelliteHealth; + + /** Satellite ephemeris time. */ + @NonNull private final SatelliteEphemerisTime mSatelliteEphemerisTime; + + private GalileoSatelliteEphemeris(Builder builder) { + // Allow satelliteCodeNumber beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSatelliteCodeNumber >= 1); + Preconditions.checkNotNull( + builder.mSatelliteClockModels, "SatelliteClockModels cannot be null"); + Preconditions.checkNotNull( + builder.mSatelliteOrbitModel, "SatelliteOrbitModel cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteHealth, "SatelliteHealth cannot be null"); + Preconditions.checkNotNull( + builder.mSatelliteEphemerisTime, "SatelliteEphemerisTime cannot be null"); + mSatelliteCodeNumber = builder.mSatelliteCodeNumber; + final List<GalileoSatelliteClockModel> satelliteClockModels = builder.mSatelliteClockModels; + mSatelliteClockModels = Collections.unmodifiableList(new ArrayList<>(satelliteClockModels)); + mSatelliteOrbitModel = builder.mSatelliteOrbitModel; + mSatelliteHealth = builder.mSatelliteHealth; + mSatelliteEphemerisTime = builder.mSatelliteEphemerisTime; + } + + /** Returns the satellite code number. */ + @IntRange(from = 1, to = 36) + public int getSatelliteCodeNumber() { + return mSatelliteCodeNumber; + } + + /** Returns the list of satellite clock models. */ + @NonNull + public List<GalileoSatelliteClockModel> getSatelliteClockModels() { + return mSatelliteClockModels; + } + + /** Returns the satellite orbit model. */ + @NonNull + public KeplerianOrbitModel getSatelliteOrbitModel() { + return mSatelliteOrbitModel; + } + + /** Returns the satellite health. */ + @NonNull + public GalileoSvHealth getSatelliteHealth() { + return mSatelliteHealth; + } + + /** Returns the satellite ephemeris time. */ + @NonNull + public SatelliteEphemerisTime getSatelliteEphemerisTime() { + return mSatelliteEphemerisTime; + } + + public static final @NonNull Creator<GalileoSatelliteEphemeris> CREATOR = + new Creator<GalileoSatelliteEphemeris>() { + @Override + @NonNull + public GalileoSatelliteEphemeris createFromParcel(Parcel in) { + final GalileoSatelliteEphemeris.Builder galileoSatelliteEphemeris = + new Builder(); + galileoSatelliteEphemeris.setSatelliteCodeNumber(in.readInt()); + List<GalileoSatelliteClockModel> satelliteClockModels = new ArrayList<>(); + in.readTypedList(satelliteClockModels, GalileoSatelliteClockModel.CREATOR); + galileoSatelliteEphemeris.setSatelliteClockModels(satelliteClockModels); + galileoSatelliteEphemeris.setSatelliteOrbitModel( + in.readTypedObject(KeplerianOrbitModel.CREATOR)); + galileoSatelliteEphemeris.setSatelliteHealth( + in.readTypedObject(GalileoSvHealth.CREATOR)); + galileoSatelliteEphemeris.setSatelliteEphemerisTime( + in.readTypedObject(SatelliteEphemerisTime.CREATOR)); + return galileoSatelliteEphemeris.build(); + } + + @Override + public GalileoSatelliteEphemeris[] newArray(int size) { + return new GalileoSatelliteEphemeris[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mSatelliteCodeNumber); + parcel.writeTypedList(mSatelliteClockModels, flags); + parcel.writeTypedObject(mSatelliteOrbitModel, flags); + parcel.writeTypedObject(mSatelliteHealth, flags); + parcel.writeTypedObject(mSatelliteEphemerisTime, flags); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GalileoSatelliteEphemeris["); + builder.append("satelliteCodeNumber = ").append(mSatelliteCodeNumber); + builder.append(", satelliteClockModels = ").append(mSatelliteClockModels); + builder.append(", satelliteOrbitModel = ").append(mSatelliteOrbitModel); + builder.append(", satelliteHealth = ").append(mSatelliteHealth); + builder.append(", satelliteEphemerisTime = ").append(mSatelliteEphemerisTime); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GalileoSatelliteEphemeris}. */ + public static final class Builder { + private int mSatelliteCodeNumber; + private List<GalileoSatelliteClockModel> mSatelliteClockModels; + private KeplerianOrbitModel mSatelliteOrbitModel; + private GalileoSvHealth mSatelliteHealth; + private SatelliteEphemerisTime mSatelliteEphemerisTime; + + /** Sets the satellite code number. */ + @NonNull + public Builder setSatelliteCodeNumber( + @IntRange(from = 1, to = 36) int satelliteCodeNumber) { + mSatelliteCodeNumber = satelliteCodeNumber; + return this; + } + + /** Sets the array of satellite clock model. */ + @NonNull + public Builder setSatelliteClockModels( + @NonNull List<GalileoSatelliteClockModel> satelliteClockModels) { + mSatelliteClockModels = satelliteClockModels; + return this; + } + + /** Sets the satellite orbit model. */ + @NonNull + public Builder setSatelliteOrbitModel(@NonNull KeplerianOrbitModel satelliteOrbitModel) { + mSatelliteOrbitModel = satelliteOrbitModel; + return this; + } + + /** Sets the satellite health. */ + @NonNull + public Builder setSatelliteHealth(@NonNull GalileoSvHealth satelliteHealth) { + mSatelliteHealth = satelliteHealth; + return this; + } + + /** Sets the satellite ephemeris time. */ + @NonNull + public Builder setSatelliteEphemerisTime( + @NonNull SatelliteEphemerisTime satelliteEphemerisTime) { + mSatelliteEphemerisTime = satelliteEphemerisTime; + return this; + } + + /** Builds a {@link GalileoSatelliteEphemeris} instance as specified by this builder. */ + @NonNull + public GalileoSatelliteEphemeris build() { + return new GalileoSatelliteEphemeris(this); + } + } + + /** + * A class contains the set of parameters needed for Galileo satellite health. + * + * <p>This is defined in Galileo-OS-SIS-ICD 5.1.9.3. + */ + public static final class GalileoSvHealth implements Parcelable { + /** E1-B data validity status. */ + private int mDataValidityStatusE1b; + + /** E1-B/C signal health status. */ + private int mSignalHealthStatusE1b; + + /** E5a data validity status. */ + private int mDataValidityStatusE5a; + + /** E5a signal health status. */ + private int mSignalHealthStatusE5a; + + /** E5b data validity status. */ + private int mDataValidityStatusE5b; + + /** E5b signal health status. */ + private int mSignalHealthStatusE5b; + + private GalileoSvHealth(Builder builder) { + Preconditions.checkArgumentInRange( + builder.mDataValidityStatusE1b, 0, 1, "DataValidityStatusE1b"); + Preconditions.checkArgumentInRange( + builder.mSignalHealthStatusE1b, 0, 3, "SignalHealthStatusE1b"); + Preconditions.checkArgumentInRange( + builder.mDataValidityStatusE5a, 0, 1, "DataValidityStatusE5a"); + Preconditions.checkArgumentInRange( + builder.mSignalHealthStatusE5a, 0, 3, "SignalHealthStatusE5a"); + Preconditions.checkArgumentInRange( + builder.mDataValidityStatusE5b, 0, 1, "DataValidityStatusE5b"); + Preconditions.checkArgumentInRange( + builder.mSignalHealthStatusE5b, 0, 3, "SignalHealthStatusE5b"); + mDataValidityStatusE1b = builder.mDataValidityStatusE1b; + mSignalHealthStatusE1b = builder.mSignalHealthStatusE1b; + mDataValidityStatusE5a = builder.mDataValidityStatusE5a; + mSignalHealthStatusE5a = builder.mSignalHealthStatusE5a; + mDataValidityStatusE5b = builder.mDataValidityStatusE5b; + mSignalHealthStatusE5b = builder.mSignalHealthStatusE5b; + } + + /** Returns the E1-B data validity status. */ + @IntRange(from = 0, to = 1) + public int getDataValidityStatusE1b() { + return mDataValidityStatusE1b; + } + + /** Returns the E1-B/C signal health status. */ + @IntRange(from = 0, to = 3) + public int getSignalHealthStatusE1b() { + return mSignalHealthStatusE1b; + } + + /** Returns the E5a data validity status. */ + @IntRange(from = 0, to = 1) + public int getDataValidityStatusE5a() { + return mDataValidityStatusE5a; + } + + /** Returns the E5a signal health status. */ + @IntRange(from = 0, to = 3) + public int getSignalHealthStatusE5a() { + return mSignalHealthStatusE5a; + } + + /** Returns the E5b data validity status. */ + @IntRange(from = 0, to = 1) + public int getDataValidityStatusE5b() { + return mDataValidityStatusE5b; + } + + /** Returns the E5b signal health status. */ + @IntRange(from = 0, to = 3) + public int getSignalHealthStatusE5b() { + return mSignalHealthStatusE5b; + } + + public static final @NonNull Creator<GalileoSvHealth> CREATOR = + new Creator<GalileoSvHealth>() { + @Override + @NonNull + public GalileoSvHealth createFromParcel(Parcel in) { + final GalileoSvHealth.Builder galileoSvHealth = new Builder(); + galileoSvHealth.setDataValidityStatusE1b(in.readInt()); + galileoSvHealth.setSignalHealthStatusE1b(in.readInt()); + galileoSvHealth.setDataValidityStatusE5a(in.readInt()); + galileoSvHealth.setSignalHealthStatusE5a(in.readInt()); + galileoSvHealth.setDataValidityStatusE5b(in.readInt()); + galileoSvHealth.setSignalHealthStatusE5b(in.readInt()); + return galileoSvHealth.build(); + } + + @Override + public GalileoSvHealth[] newArray(int size) { + return new GalileoSvHealth[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mDataValidityStatusE1b); + parcel.writeInt(mSignalHealthStatusE1b); + parcel.writeInt(mDataValidityStatusE5a); + parcel.writeInt(mSignalHealthStatusE5a); + parcel.writeInt(mDataValidityStatusE5b); + parcel.writeInt(mSignalHealthStatusE5b); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GalileoSvHealth["); + builder.append("dataValidityStatusE1b = ").append(mDataValidityStatusE1b); + builder.append(", signalHealthStatusE1b = ").append(mSignalHealthStatusE1b); + builder.append(", dataValidityStatusE5a = ").append(mDataValidityStatusE5a); + builder.append(", signalHealthStatusE5a = ").append(mSignalHealthStatusE5a); + builder.append(", dataValidityStatusE5b = ").append(mDataValidityStatusE5b); + builder.append(", signalHealthStatusE5b = ").append(mSignalHealthStatusE5b); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GalileoSvHealth}. */ + public static final class Builder { + private int mDataValidityStatusE1b; + private int mSignalHealthStatusE1b; + private int mDataValidityStatusE5a; + private int mSignalHealthStatusE5a; + private int mDataValidityStatusE5b; + private int mSignalHealthStatusE5b; + + /** Sets the E1-B data validity status. */ + @NonNull + public Builder setDataValidityStatusE1b( + @IntRange(from = 0, to = 1) int dataValidityStatusE1b) { + mDataValidityStatusE1b = dataValidityStatusE1b; + return this; + } + + /** Sets the E1-B/C signal health status. */ + @NonNull + public Builder setSignalHealthStatusE1b( + @IntRange(from = 0, to = 3) int signalHealthStatusE1b) { + mSignalHealthStatusE1b = signalHealthStatusE1b; + return this; + } + + /** Sets the E5a data validity status. */ + @NonNull + public Builder setDataValidityStatusE5a( + @IntRange(from = 0, to = 1) int dataValidityStatusE5a) { + mDataValidityStatusE5a = dataValidityStatusE5a; + return this; + } + + /** Sets the E5a signal health status. */ + @NonNull + public Builder setSignalHealthStatusE5a( + @IntRange(from = 0, to = 3) int signalHealthStatusE5a) { + mSignalHealthStatusE5a = signalHealthStatusE5a; + return this; + } + + /** Sets the E5b data validity status. */ + @NonNull + public Builder setDataValidityStatusE5b( + @IntRange(from = 0, to = 1) int dataValidityStatusE5b) { + mDataValidityStatusE5b = dataValidityStatusE5b; + return this; + } + + /** Sets the E5b signal health status. */ + @NonNull + public Builder setSignalHealthStatusE5b( + @IntRange(from = 0, to = 3) int signalHealthStatusE5b) { + mSignalHealthStatusE5b = signalHealthStatusE5b; + return this; + } + + /** Builds a {@link GalileoSvHealth}. */ + @NonNull + public GalileoSvHealth build() { + return new GalileoSvHealth(this); + } + } + } + + /** + * A class contains the set of parameters needed for Galileo satellite clock correction. + * + * <p>This is defined in Galileo-OS-SIS-ICD 5.1.3. + */ + public static final class GalileoSatelliteClockModel implements Parcelable { + + /** + * The type of the satellite clock. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({TYPE_UNDEFINED, TYPE_FNAV, TYPE_INAV}) + public @interface SatelliteClockType {} + + /** + * The following enumerations must be in sync with the values declared in + * GalileoSatelliteEphemeris.aidl. + */ + + /** The type of the satellite clock is unknown. */ + public static final int TYPE_UNDEFINED = 0; + + /** The type of the satellite clock is FNAV. */ + public static final int TYPE_FNAV = 1; + + /** The type of the satellite clock is INAV. */ + public static final int TYPE_INAV = 2; + + /** + * Time of the clock in seconds since Galileo epoch. + * + * <p>Corresponds to the 'Epoch' field within the 'SV/EPOCH/SV CLK' record of Galileo + * navigation message in RINEX 3.05 Table A8. + */ + private final long mTimeOfClockSeconds; + + /** SV clock bias correction coefficient in seconds. */ + private double mAf0; + + /** SV clock drift correction coefficient in seconds per second. */ + private double mAf1; + + /** SV clock drift rate correction coefficient in seconds per second squared. */ + private double mAf2; + + /** + * Broadcast group delay in seconds. + * + * <p>This is defined in Galileo-OS-SIS-ICD 5.1.5. + */ + private double mBgdSeconds; + + /** + * Signal in space accuracy in meters. + * + * <p>This is defined in Galileo-OS-SIS-ICD 5.1.12. + */ + private double mSisaMeters; + + /** Type of satellite clock . */ + private final @SatelliteClockType int mSatelliteClockType; + + private GalileoSatelliteClockModel(Builder builder) { + Preconditions.checkArgument(builder.mTimeOfClockSeconds >= 0); + Preconditions.checkArgumentInRange(builder.mAf0, -0.0625f, 0.0625f, "AF0"); + Preconditions.checkArgumentInRange(builder.mAf1, -1.5e-8f, 1.5e-8f, "AF1"); + Preconditions.checkArgumentInRange(builder.mAf2, -5.56e-17f, 5.56e-17f, "AF2"); + Preconditions.checkArgumentInRange( + builder.mBgdSeconds, -1.2e-7f, 1.2e-7f, "BgdSeconds"); + Preconditions.checkArgument(builder.mSisaMeters >= 0.0f); + Preconditions.checkArgumentInRange( + builder.mSatelliteClockType, TYPE_UNDEFINED, TYPE_INAV, "SatelliteClockType"); + mTimeOfClockSeconds = builder.mTimeOfClockSeconds; + mAf0 = builder.mAf0; + mAf1 = builder.mAf1; + mAf2 = builder.mAf2; + mBgdSeconds = builder.mBgdSeconds; + mSisaMeters = builder.mSisaMeters; + mSatelliteClockType = builder.mSatelliteClockType; + } + + /** Returns the time of the clock in seconds since Galileo epoch. */ + @IntRange(from = 0) + public long getTimeOfClockSeconds() { + return mTimeOfClockSeconds; + } + + /** Returns the SV clock bias correction coefficient in seconds. */ + @FloatRange(from = -0.0625f, to = 0.0625f) + public double getAf0() { + return mAf0; + } + + /** Returns the SV clock drift correction coefficient in seconds per second. */ + @FloatRange(from = -1.5e-8f, to = 1.5e-8f) + public double getAf1() { + return mAf1; + } + + /** Returns the SV clock drift rate correction coefficient in seconds per second squared. */ + @FloatRange(from = -5.56e-17f, to = 5.56e-17f) + public double getAf2() { + return mAf2; + } + + /** Returns the broadcast group delay in seconds. */ + @FloatRange(from = -1.2e-7f, to = 1.2e-7f) + public double getBgdSeconds() { + return mBgdSeconds; + } + + /** Returns the signal in space accuracy in meters. */ + @FloatRange(from = 0.0f) + public double getSisaMeters() { + return mSisaMeters; + } + + /** Returns the type of satellite clock. */ + public @SatelliteClockType int getSatelliteClockType() { + return mSatelliteClockType; + } + + public static final @NonNull Creator<GalileoSatelliteClockModel> CREATOR = + new Creator<GalileoSatelliteClockModel>() { + @Override + @NonNull + public GalileoSatelliteClockModel createFromParcel(Parcel in) { + final GalileoSatelliteClockModel.Builder galileoSatelliteClockModel = + new Builder(); + galileoSatelliteClockModel.setTimeOfClockSeconds(in.readLong()); + galileoSatelliteClockModel.setAf0(in.readDouble()); + galileoSatelliteClockModel.setAf1(in.readDouble()); + galileoSatelliteClockModel.setAf2(in.readDouble()); + galileoSatelliteClockModel.setBgdSeconds(in.readDouble()); + galileoSatelliteClockModel.setSisaMeters(in.readDouble()); + galileoSatelliteClockModel.setSatelliteClockType(in.readInt()); + return galileoSatelliteClockModel.build(); + } + + @Override + public GalileoSatelliteClockModel[] newArray(int size) { + return new GalileoSatelliteClockModel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeLong(mTimeOfClockSeconds); + parcel.writeDouble(mAf0); + parcel.writeDouble(mAf1); + parcel.writeDouble(mAf2); + parcel.writeDouble(mBgdSeconds); + parcel.writeDouble(mSisaMeters); + parcel.writeInt(mSatelliteClockType); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GalileoSatelliteClockModel["); + builder.append("timeOfClockSeconds = ").append(mTimeOfClockSeconds); + builder.append(", af0 = ").append(mAf0); + builder.append(", af1 = ").append(mAf1); + builder.append(", af2 = ").append(mAf2); + builder.append(", bgdSeconds = ").append(mBgdSeconds); + builder.append(", sisaMeters = ").append(mSisaMeters); + builder.append(", satelliteClockType = ").append(mSatelliteClockType); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GalileoSatelliteClockModel}. */ + public static final class Builder { + private long mTimeOfClockSeconds; + private double mAf0; + private double mAf1; + private double mAf2; + private double mBgdSeconds; + private double mSisaMeters; + private @SatelliteClockType int mSatelliteClockType; + + /** Sets the time of the clock in seconds since Galileo epoch. */ + @NonNull + public Builder setTimeOfClockSeconds(@IntRange(from = 0) long timeOfClockSeconds) { + mTimeOfClockSeconds = timeOfClockSeconds; + return this; + } + + /** Sets the SV clock bias correction coefficient in seconds. */ + @NonNull + public Builder setAf0(@FloatRange(from = -0.0625f, to = 0.0625f) double af0) { + mAf0 = af0; + return this; + } + + /** Sets the SV clock drift correction coefficient in seconds per second. */ + @NonNull + public Builder setAf1(@FloatRange(from = -1.5e-8f, to = 1.5e-8f) double af1) { + mAf1 = af1; + return this; + } + + /** + * Sets the SV clock drift rate correction coefficient in seconds per second squared. + */ + @NonNull + public Builder setAf2(@FloatRange(from = -5.56e-17f, to = 5.56e-17f) double af2) { + mAf2 = af2; + return this; + } + + /** Sets the broadcast group delay in seconds. */ + @NonNull + public Builder setBgdSeconds( + @FloatRange(from = -1.2e-7f, to = 1.2e-7f) double bgdSeconds) { + mBgdSeconds = bgdSeconds; + return this; + } + + /** Sets the signal in space accuracy in meters. */ + @NonNull + public Builder setSisaMeters(@FloatRange(from = 0.0f) double sisaMeters) { + mSisaMeters = sisaMeters; + return this; + } + + /** Sets the type of satellite clock. */ + @NonNull + public Builder setSatelliteClockType(@SatelliteClockType int satelliteClockType) { + mSatelliteClockType = satelliteClockType; + return this; + } + + /** + * Builds a {@link GalileoSatelliteClockModel} instance as specified by this builder. + */ + @NonNull + public GalileoSatelliteClockModel build() { + return new GalileoSatelliteClockModel(this); + } + } + } +} diff --git a/location/java/android/location/GlonassAlmanac.java b/location/java/android/location/GlonassAlmanac.java new file mode 100644 index 000000000000..861dc5d257c4 --- /dev/null +++ b/location/java/android/location/GlonassAlmanac.java @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains Glonass almanac data. + * + * <p>This is defined in Glonass ICD v5.1 section 4.5. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GlonassAlmanac implements Parcelable { + + /** Almanac issue date in milliseconds (UTC) */ + private final long mIssueDateMillis; + + /** List of GlonassSatelliteAlmanacs. */ + @NonNull private final List<GlonassSatelliteAlmanac> mSatelliteAlmanacs; + + /** + * Constructor for GlonassAlmanac. + * + * @param issueDateMillis The almanac issue date in milliseconds (UTC). + * @param satelliteAlmanacs The list of GlonassSatelliteAlmanac. + */ + public GlonassAlmanac( + @IntRange(from = 0) long issueDateMillis, + @NonNull List<GlonassSatelliteAlmanac> satelliteAlmanacs) { + Preconditions.checkArgument(issueDateMillis >= 0); + Preconditions.checkNotNull(satelliteAlmanacs, "satelliteAlmanacs cannot be null"); + mIssueDateMillis = issueDateMillis; + mSatelliteAlmanacs = Collections.unmodifiableList(new ArrayList<>(satelliteAlmanacs)); + } + + /** Returns the almanac issue date in milliseconds (UTC). */ + @IntRange(from = 0) + public long getIssueDateMillis() { + return mIssueDateMillis; + } + + /** Returns the list of GlonassSatelliteAlmanacs. */ + @NonNull + public List<GlonassSatelliteAlmanac> getSatelliteAlmanacs() { + return mSatelliteAlmanacs; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mIssueDateMillis); + dest.writeTypedList(mSatelliteAlmanacs); + } + + public static final @NonNull Parcelable.Creator<GlonassAlmanac> CREATOR = + new Parcelable.Creator<GlonassAlmanac>() { + @Override + public GlonassAlmanac createFromParcel(@NonNull Parcel in) { + long issueDateMillis = in.readLong(); + List<GlonassSatelliteAlmanac> satelliteAlmanacs = new ArrayList<>(); + in.readTypedList(satelliteAlmanacs, GlonassSatelliteAlmanac.CREATOR); + return new GlonassAlmanac(issueDateMillis, satelliteAlmanacs); + } + + @Override + public GlonassAlmanac[] newArray(int size) { + return new GlonassAlmanac[size]; + } + }; + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GlonassAlmanac["); + builder.append("issueDateMillis = ").append(mIssueDateMillis); + builder.append(", satelliteAlmanacs = ").append(mSatelliteAlmanacs); + builder.append("]"); + return builder.toString(); + } + + /** + * A class contains Glonass satellite almanac data. + * + * <p>This is defined in Glonass ICD v5.1 section 4.5. + */ + public static final class GlonassSatelliteAlmanac implements Parcelable { + /** Slot number. */ + private final int mSlotNumber; + + /** Satellite health information (0=healthy, 1=unhealthy). */ + private final int mSvHealth; + + /** Frequency channel number. */ + private final int mFreqChannel; + + /** Coarse value of satellite time correction to GLONASS time in seconds. */ + private final double mTau; + + /** Time of first ascending node passage of satellite in seconds. */ + private final double mTLambda; + + /** Longitude of the first ascending node in semi-circles. */ + private final double mLambda; + + /** Correction to the mean value of inclination in semi-circles. */ + private final double mDeltaI; + + /** Correction to the mean value of the draconian period in seconds per orbital period */ + private final double mDeltaT; + + /** Rate of change of draconian period in seconds per orbital period squared. */ + private final double mDeltaTDot; + + /** Eccentricity. */ + private final double mEccentricity; + + /** Argument of perigee in radians. */ + private final double mOmega; + + private GlonassSatelliteAlmanac(Builder builder) { + // Allow slotNumber beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSlotNumber >= 1); + // Allow svHealth beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSvHealth >= 0); + Preconditions.checkArgumentInRange(builder.mFreqChannel, 0, 31, "FreqChannel"); + Preconditions.checkArgumentInRange(builder.mTau, -1.9e-3f, 1.9e-3f, "Tau"); + Preconditions.checkArgumentInRange(builder.mTLambda, 0.0f, 44100.0f, "TLambda"); + Preconditions.checkArgumentInRange(builder.mLambda, -1.0f, 1.0f, "Lambda"); + Preconditions.checkArgumentInRange(builder.mDeltaI, -0.067f, 0.067f, "DeltaI"); + Preconditions.checkArgumentInRange(builder.mDeltaT, -3600.0f, 3600.0f, "DeltaT"); + Preconditions.checkArgumentInRange(builder.mDeltaTDot, -0.004f, 0.004f, "DeltaTDot"); + Preconditions.checkArgumentInRange(builder.mEccentricity, 0.0f, 0.03f, "Eccentricity"); + Preconditions.checkArgumentInRange(builder.mOmega, -1.0f, 1.0f, "Omega"); + mSlotNumber = builder.mSlotNumber; + mSvHealth = builder.mSvHealth; + mFreqChannel = builder.mFreqChannel; + mTau = builder.mTau; + mTLambda = builder.mTLambda; + mLambda = builder.mLambda; + mDeltaI = builder.mDeltaI; + mDeltaT = builder.mDeltaT; + mDeltaTDot = builder.mDeltaTDot; + mEccentricity = builder.mEccentricity; + mOmega = builder.mOmega; + } + + /** Returns the slot number. */ + @IntRange(from = 1, to = 25) + public int getSlotNumber() { + return mSlotNumber; + } + + /** Returns the Satellite health information (0=healthy, 1=unhealthy). */ + @IntRange(from = 0, to = 1) + public int getSvHealth() { + return mSvHealth; + } + + /** Returns the frequency channel number. */ + @IntRange(from = 0, to = 31) + public int getFreqChannel() { + return mFreqChannel; + } + + /** Returns the coarse value of satellite time correction to GLONASS time in seconds. */ + @FloatRange(from = -1.9e-3f, to = 1.9e-3f) + public double getTau() { + return mTau; + } + + /** Returns the time of first ascending node passage of satellite in seconds. */ + @FloatRange(from = 0.0f, to = 44100.0f) + public double getTLambda() { + return mTLambda; + } + + /** Returns the longitude of the first ascending node in semi-circles. */ + @FloatRange(from = -1.0f, to = 1.0f) + public double getLambda() { + return mLambda; + } + + /** Returns the correction to the mean value of inclination in semi-circles. */ + @FloatRange(from = -0.067f, to = 0.067f) + public double getDeltaI() { + return mDeltaI; + } + + /** + * Returns the correction to the mean value of the draconian period in seconds per orbital + * period + */ + @FloatRange(from = -3600.0f, to = 3600.0f) + public double getDeltaT() { + return mDeltaT; + } + + /** Returns the rate of change of draconian period in seconds per orbital period squared. */ + @FloatRange(from = -0.004f, to = 0.004f) + public double getDeltaTDot() { + return mDeltaTDot; + } + + /** Returns the eccentricity. */ + @FloatRange(from = 0.0f, to = 0.03f) + public double getEccentricity() { + return mEccentricity; + } + + /** Returns the argument of perigee in radians. */ + @FloatRange(from = -1.0f, to = 1.0f) + public double getOmega() { + return mOmega; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSlotNumber); + dest.writeInt(mSvHealth); + dest.writeInt(mFreqChannel); + dest.writeDouble(mTau); + dest.writeDouble(mTLambda); + dest.writeDouble(mLambda); + dest.writeDouble(mDeltaI); + dest.writeDouble(mDeltaT); + dest.writeDouble(mDeltaTDot); + dest.writeDouble(mEccentricity); + dest.writeDouble(mOmega); + } + + public static final @NonNull Parcelable.Creator<GlonassSatelliteAlmanac> CREATOR = + new Parcelable.Creator<GlonassSatelliteAlmanac>() { + @Override + public GlonassSatelliteAlmanac createFromParcel(@NonNull Parcel source) { + return new GlonassSatelliteAlmanac.Builder() + .setSlotNumber(source.readInt()) + .setSvHealth(source.readInt()) + .setFreqChannel(source.readInt()) + .setTau(source.readDouble()) + .setTLambda(source.readDouble()) + .setLambda(source.readDouble()) + .setDeltaI(source.readDouble()) + .setDeltaT(source.readDouble()) + .setDeltaTDot(source.readDouble()) + .setEccentricity(source.readDouble()) + .setOmega(source.readDouble()) + .build(); + } + + @Override + public GlonassSatelliteAlmanac[] newArray(int size) { + return new GlonassSatelliteAlmanac[size]; + } + }; + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GlonassSatelliteAlmanac["); + builder.append("slotNumber = ").append(mSlotNumber); + builder.append(", svHealth = ").append(mSvHealth); + builder.append(", freqChannel = ").append(mFreqChannel); + builder.append(", tau = ").append(mTau); + builder.append(", tLambda = ").append(mTLambda); + builder.append(", lambda = ").append(mLambda); + builder.append(", deltaI = ").append(mDeltaI); + builder.append(", deltaT = ").append(mDeltaT); + builder.append(", deltaTDot = ").append(mDeltaTDot); + builder.append(", eccentricity = ").append(mEccentricity); + builder.append(", omega = ").append(mOmega); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GlonassSatelliteAlmanac}. */ + public static final class Builder { + private int mSlotNumber; + private int mSvHealth; + private int mFreqChannel; + private double mTau; + private double mTLambda; + private double mLambda; + private double mDeltaI; + private double mDeltaT; + private double mDeltaTDot; + private double mEccentricity; + private double mOmega; + + /** Sets the slot number. */ + @NonNull + public Builder setSlotNumber(@IntRange(from = 1, to = 25) int slotNumber) { + mSlotNumber = slotNumber; + return this; + } + + /** Sets the Satellite health information (0=healthy, 1=unhealthy). */ + @NonNull + public Builder setSvHealth(@IntRange(from = 0, to = 1) int svHealth) { + mSvHealth = svHealth; + return this; + } + + /** Sets the frequency channel number. */ + @NonNull + public Builder setFreqChannel(@IntRange(from = 0, to = 31) int freqChannel) { + mFreqChannel = freqChannel; + return this; + } + + /** Sets the coarse value of satellite time correction to GLONASS time in seconds. */ + @NonNull + public Builder setTau(@FloatRange(from = -1.9e-3f, to = 1.9e-3f) double tau) { + mTau = tau; + return this; + } + + /** Sets the time of first ascending node passage of satellite in seconds. */ + @NonNull + public Builder setTLambda(@FloatRange(from = 0.0f, to = 44100.0f) double tLambda) { + mTLambda = tLambda; + return this; + } + + /** Sets the longitude of the first ascending node in semi-circles. */ + @NonNull + public Builder setLambda(@FloatRange(from = -1.0f, to = 1.0f) double lambda) { + mLambda = lambda; + return this; + } + + /** Sets the correction to the mean value of inclination in semi-circles. */ + @NonNull + public Builder setDeltaI(@FloatRange(from = -0.067f, to = 0.067f) double deltaI) { + mDeltaI = deltaI; + return this; + } + + /** + * Sets the correction to the mean value of the draconian period in seconds per orbital + * period. + */ + @NonNull + public Builder setDeltaT(@FloatRange(from = -3600.0f, to = 3600.0f) double deltaT) { + mDeltaT = deltaT; + return this; + } + + /** + * Sets the rate of change of draconian period in seconds per orbital period squared. + */ + @NonNull + public Builder setDeltaTDot(@FloatRange(from = -0.004f, to = 0.004f) double deltaTDot) { + mDeltaTDot = deltaTDot; + return this; + } + + /** Sets the eccentricity. */ + @NonNull + public Builder setEccentricity( + @FloatRange(from = 0.0f, to = 0.03f) double eccentricity) { + mEccentricity = eccentricity; + return this; + } + + /** Sets the argument of perigee in radians. */ + @NonNull + public Builder setOmega(@FloatRange(from = -1.0f, to = 1.0f) double omega) { + mOmega = omega; + return this; + } + + /** Builds a {@link GlonassSatelliteAlmanac}. */ + @NonNull + public GlonassSatelliteAlmanac build() { + return new GlonassSatelliteAlmanac(this); + } + } + } +} diff --git a/location/java/android/location/GlonassAssistance.java b/location/java/android/location/GlonassAssistance.java new file mode 100644 index 000000000000..cc0820197d8d --- /dev/null +++ b/location/java/android/location/GlonassAssistance.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.location.GnssAssistance.GnssSatelliteCorrections; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains Glonass assistance. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GlonassAssistance implements Parcelable { + + /** The Glonass almanac. */ + @Nullable private final GlonassAlmanac mAlmanac; + + /** The UTC model. */ + @Nullable private final UtcModel mUtcModel; + + /** The list of time models. */ + @NonNull private final List<TimeModel> mTimeModels; + + /** The list of Glonass ephemeris. */ + @NonNull private final List<GlonassSatelliteEphemeris> mSatelliteEphemeris; + + /** The list of Glonass satellite corrections. */ + @NonNull private final List<GnssSatelliteCorrections> mSatelliteCorrections; + + private GlonassAssistance(Builder builder) { + mAlmanac = builder.mAlmanac; + mUtcModel = builder.mUtcModel; + if (builder.mTimeModels != null) { + mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); + } else { + mTimeModels = new ArrayList<>(); + } + if (builder.mSatelliteEphemeris != null) { + mSatelliteEphemeris = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteEphemeris)); + } else { + mSatelliteEphemeris = new ArrayList<>(); + } + if (builder.mSatelliteCorrections != null) { + mSatelliteCorrections = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteCorrections)); + } else { + mSatelliteCorrections = new ArrayList<>(); + } + } + + /** Returns the Glonass almanac. */ + @Nullable + public GlonassAlmanac getAlmanac() { + return mAlmanac; + } + + /** Returns the UTC model. */ + @Nullable + public UtcModel getUtcModel() { + return mUtcModel; + } + + /** Returns the list of time models. */ + @NonNull + public List<TimeModel> getTimeModels() { + return mTimeModels; + } + + /** Returns the list of Glonass satellite ephemeris. */ + @NonNull + public List<GlonassSatelliteEphemeris> getSatelliteEphemeris() { + return mSatelliteEphemeris; + } + + /** Returns the list of Glonass satellite corrections. */ + @NonNull + public List<GnssSatelliteCorrections> getSatelliteCorrections() { + return mSatelliteCorrections; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mAlmanac, flags); + dest.writeTypedObject(mUtcModel, flags); + dest.writeTypedList(mTimeModels); + dest.writeTypedList(mSatelliteEphemeris); + dest.writeTypedList(mSatelliteCorrections); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GlonassAssistance["); + builder.append("almanac = ").append(mAlmanac); + builder.append(", utcModel = ").append(mUtcModel); + builder.append(", timeModels = ").append(mTimeModels); + builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); + builder.append(", satelliteCorrections = ").append(mSatelliteCorrections); + builder.append("]"); + return builder.toString(); + } + + public static final @NonNull Creator<GlonassAssistance> CREATOR = + new Creator<GlonassAssistance>() { + @Override + public GlonassAssistance createFromParcel(Parcel in) { + return new GlonassAssistance.Builder() + .setAlmanac(in.readTypedObject(GlonassAlmanac.CREATOR)) + .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) + .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) + .setSatelliteEphemeris( + in.createTypedArrayList(GlonassSatelliteEphemeris.CREATOR)) + .setSatelliteCorrections( + in.createTypedArrayList(GnssSatelliteCorrections.CREATOR)) + .build(); + } + + @Override + public GlonassAssistance[] newArray(int size) { + return new GlonassAssistance[size]; + } + }; + + /** Builder for {@link GlonassAssistance}. */ + public static final class Builder { + private GlonassAlmanac mAlmanac; + private UtcModel mUtcModel; + private List<TimeModel> mTimeModels; + private List<GlonassSatelliteEphemeris> mSatelliteEphemeris; + private List<GnssSatelliteCorrections> mSatelliteCorrections; + + /** Sets the Glonass almanac. */ + @NonNull + public Builder setAlmanac( + @Nullable @SuppressLint("NullableCollection") GlonassAlmanac almanac) { + mAlmanac = almanac; + return this; + } + + /** Sets the UTC model. */ + @NonNull + public Builder setUtcModel( + @Nullable @SuppressLint("NullableCollection") UtcModel utcModel) { + mUtcModel = utcModel; + return this; + } + + /** Sets the list of time models. */ + @NonNull + public Builder setTimeModels( + @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + mTimeModels = timeModels; + return this; + } + + /** Sets the list of Glonass satellite ephemeris. */ + @NonNull + public Builder setSatelliteEphemeris( + @Nullable @SuppressLint("NullableCollection") + List<GlonassSatelliteEphemeris> satelliteEphemeris) { + mSatelliteEphemeris = satelliteEphemeris; + return this; + } + + /** Sets the list of Glonass satellite corrections. */ + @NonNull + public Builder setSatelliteCorrections( + @Nullable @SuppressLint("NullableCollection") + List<GnssSatelliteCorrections> satelliteCorrections) { + mSatelliteCorrections = satelliteCorrections; + return this; + } + + /** Builds the {@link GlonassAssistance}. */ + @NonNull + public GlonassAssistance build() { + return new GlonassAssistance(this); + } + } +} diff --git a/location/java/android/location/GlonassSatelliteEphemeris.java b/location/java/android/location/GlonassSatelliteEphemeris.java new file mode 100644 index 000000000000..77a6ebb50cfb --- /dev/null +++ b/location/java/android/location/GlonassSatelliteEphemeris.java @@ -0,0 +1,623 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains ephemeris parameters specific to Glonass satellites. + * + * <p>This is defined in RINEX 3.05 APPENDIX 10 and Glonass ICD v5.1 section 4.4. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GlonassSatelliteEphemeris implements Parcelable { + + /** L1/Satellite system (R), satellite number (slot number in sat. constellation). */ + private final int mSlotNumber; + + /** Health state (0=healthy, 1=unhealthy). */ + private final int mHealthState; + + /** Message frame time in seconds of the UTC week (tk+nd*86400). */ + private final double mFrameTimeSeconds; + + /** Age of current information in days (E). */ + private final int mAgeInDays; + + /** Satellite clock model. */ + @NonNull private final GlonassSatelliteClockModel mSatelliteClockModel; + + /** Satellite orbit model. */ + @NonNull private final GlonassSatelliteOrbitModel mSatelliteOrbitModel; + + private GlonassSatelliteEphemeris(Builder builder) { + // Allow SlotNumber beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSlotNumber >= 1); + // Allow HealthState beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mHealthState >= 0); + Preconditions.checkArgument(builder.mFrameTimeSeconds >= 0.0f); + Preconditions.checkArgumentInRange(builder.mAgeInDays, 0, 31, "AgeInDays"); + Preconditions.checkNotNull( + builder.mSatelliteClockModel, "SatelliteClockModel cannot be null"); + Preconditions.checkNotNull( + builder.mSatelliteOrbitModel, "SatelliteOrbitModel cannot be null"); + mSlotNumber = builder.mSlotNumber; + mHealthState = builder.mHealthState; + mFrameTimeSeconds = builder.mFrameTimeSeconds; + mAgeInDays = builder.mAgeInDays; + mSatelliteClockModel = builder.mSatelliteClockModel; + mSatelliteOrbitModel = builder.mSatelliteOrbitModel; + } + + /** + * Returns the L1/Satellite system (R), satellite number (slot number in sat. constellation). + */ + @IntRange(from = 1, to = 25) + public int getSlotNumber() { + return mSlotNumber; + } + + /** Returns the health state (0=healthy, 1=unhealthy). */ + @IntRange(from = 0, to = 1) + public int getHealthState() { + return mHealthState; + } + + /** Returns the message frame time in seconds of the UTC week (tk+nd*86400). */ + @FloatRange(from = 0.0f) + public double getFrameTimeSeconds() { + return mFrameTimeSeconds; + } + + /** Returns the age of current information in days (E). */ + @IntRange(from = 0, to = 31) + public int getAgeInDays() { + return mAgeInDays; + } + + /** Returns the satellite clock model. */ + @NonNull + public GlonassSatelliteClockModel getSatelliteClockModel() { + return mSatelliteClockModel; + } + + /** Returns the satellite orbit model. */ + @NonNull + public GlonassSatelliteOrbitModel getSatelliteOrbitModel() { + return mSatelliteOrbitModel; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSlotNumber); + dest.writeInt(mHealthState); + dest.writeDouble(mFrameTimeSeconds); + dest.writeInt(mAgeInDays); + dest.writeTypedObject(mSatelliteClockModel, flags); + dest.writeTypedObject(mSatelliteOrbitModel, flags); + } + + public static final @NonNull Parcelable.Creator<GlonassSatelliteEphemeris> CREATOR = + new Parcelable.Creator<GlonassSatelliteEphemeris>() { + @Override + public GlonassSatelliteEphemeris createFromParcel(@NonNull Parcel source) { + return new GlonassSatelliteEphemeris.Builder() + .setSlotNumber(source.readInt()) + .setHealthState(source.readInt()) + .setFrameTimeSeconds(source.readDouble()) + .setAgeInDays(source.readInt()) + .setSatelliteClockModel( + source.readTypedObject(GlonassSatelliteClockModel.CREATOR)) + .setSatelliteOrbitModel( + source.readTypedObject(GlonassSatelliteOrbitModel.CREATOR)) + .build(); + } + + @Override + public GlonassSatelliteEphemeris[] newArray(int size) { + return new GlonassSatelliteEphemeris[size]; + } + }; + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GlonassSatelliteEphemeris["); + builder.append("slotNumber = ").append(mSlotNumber); + builder.append(", healthState = ").append(mHealthState); + builder.append(", frameTimeSeconds = ").append(mFrameTimeSeconds); + builder.append(", ageInDays = ").append(mAgeInDays); + builder.append(", satelliteClockModel = ").append(mSatelliteClockModel); + builder.append(", satelliteOrbitModel = ").append(mSatelliteOrbitModel); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GlonassSatelliteEphemeris}. */ + public static final class Builder { + private int mSlotNumber; + private int mHealthState; + private double mFrameTimeSeconds; + private int mAgeInDays; + private GlonassSatelliteClockModel mSatelliteClockModel; + private GlonassSatelliteOrbitModel mSatelliteOrbitModel; + + /** + * Sets the L1/Satellite system (R), satellite number (slot number in sat. constellation). + */ + @NonNull + public Builder setSlotNumber(@IntRange(from = 1, to = 25) int slotNumber) { + mSlotNumber = slotNumber; + return this; + } + + /** Sets the health state (0=healthy, 1=unhealthy). */ + @NonNull + public Builder setHealthState(@IntRange(from = 0, to = 1) int healthState) { + mHealthState = healthState; + return this; + } + + /** Sets the message frame time in seconds of the UTC week (tk+nd*86400). */ + @NonNull + public Builder setFrameTimeSeconds(@FloatRange(from = 0.0f) double frameTimeSeconds) { + mFrameTimeSeconds = frameTimeSeconds; + return this; + } + + /** Sets the age of current information in days (E). */ + @NonNull + public Builder setAgeInDays(@IntRange(from = 0, to = 31) int ageInDays) { + mAgeInDays = ageInDays; + return this; + } + + /** Sets the satellite clock model. */ + @NonNull + public Builder setSatelliteClockModel( + @NonNull GlonassSatelliteClockModel satelliteClockModel) { + mSatelliteClockModel = satelliteClockModel; + return this; + } + + /** Sets the satellite orbit model. */ + @NonNull + public Builder setSatelliteOrbitModel( + @NonNull GlonassSatelliteOrbitModel satelliteOrbitModel) { + mSatelliteOrbitModel = satelliteOrbitModel; + return this; + } + + /** Builds a {@link GlonassSatelliteEphemeris}. */ + @NonNull + public GlonassSatelliteEphemeris build() { + return new GlonassSatelliteEphemeris(this); + } + } + + /** + * A class contains the set of parameters needed for Glonass satellite clock correction. + * + * <p>This is defined in RINEX 3.05 APPENDIX 10 and Glonass ICD v5.1 section 4.4. + */ + public static final class GlonassSatelliteClockModel implements Parcelable { + /** + * Time of the clock in seconds (UTC) + * + * <p>Corresponds to the 'Epoch' field within the 'SV/EPOCH/SV CLK' record of Glonass + * navigation message in RINEX 3.05 Table A10. + */ + private final long mTimeOfClockSeconds; + + /** Clock bias in seconds (-TauN). */ + private final double mClockBias; + + /** Frequency bias (+GammaN). */ + private final double mFrequencyBias; + + /** Frequency number. */ + private final int mFrequencyNumber; + + private GlonassSatelliteClockModel(Builder builder) { + Preconditions.checkArgument(builder.mTimeOfClockSeconds >= 0); + Preconditions.checkArgumentInRange(builder.mClockBias, -0.002f, 0.002f, "ClockBias"); + Preconditions.checkArgumentInRange( + builder.mFrequencyBias, -9.32e-10f, 9.32e-10f, "FrequencyBias"); + Preconditions.checkArgumentInRange(builder.mFrequencyNumber, -7, 6, "FrequencyNumber"); + mTimeOfClockSeconds = builder.mTimeOfClockSeconds; + mClockBias = builder.mClockBias; + mFrequencyBias = builder.mFrequencyBias; + mFrequencyNumber = builder.mFrequencyNumber; + } + + /** Returns the time of clock in seconds (UTC). */ + @IntRange(from = 0) + public long getTimeOfClockSeconds() { + return mTimeOfClockSeconds; + } + + /** Returns the clock bias in seconds (-TauN). */ + @FloatRange(from = -0.002f, to = 0.002f) + public double getClockBias() { + return mClockBias; + } + + /** Returns the frequency bias (+GammaN). */ + @FloatRange(from = -9.32e-10f, to = 9.32e-10f) + public double getFrequencyBias() { + return mFrequencyBias; + } + + /** Returns the frequency number. */ + @IntRange(from = -7, to = 6) + public int getFrequencyNumber() { + return mFrequencyNumber; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mTimeOfClockSeconds); + dest.writeDouble(mClockBias); + dest.writeDouble(mFrequencyBias); + dest.writeInt(mFrequencyNumber); + } + + public static final @NonNull Parcelable.Creator<GlonassSatelliteClockModel> CREATOR = + new Parcelable.Creator<GlonassSatelliteClockModel>() { + @Override + public GlonassSatelliteClockModel createFromParcel(@NonNull Parcel source) { + return new GlonassSatelliteClockModel.Builder() + .setTimeOfClockSeconds(source.readLong()) + .setClockBias(source.readDouble()) + .setFrequencyBias(source.readDouble()) + .setFrequencyNumber(source.readInt()) + .build(); + } + + @Override + public GlonassSatelliteClockModel[] newArray(int size) { + return new GlonassSatelliteClockModel[size]; + } + }; + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GlonassSatelliteClockModel["); + builder.append("timeOfClockSeconds = ").append(mTimeOfClockSeconds); + builder.append(", clockBias = ").append(mClockBias); + builder.append(", frequencyBias = ").append(mFrequencyBias); + builder.append(", frequencyNumber = ").append(mFrequencyNumber); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GlonassSatelliteClockModel}. */ + public static final class Builder { + private long mTimeOfClockSeconds; + private double mClockBias; + private double mFrequencyBias; + private int mFrequencyNumber; + + /** Sets the time of clock in seconds (UTC). */ + @NonNull + public Builder setTimeOfClockSeconds(@IntRange(from = 0) long timeOfClockSeconds) { + mTimeOfClockSeconds = timeOfClockSeconds; + return this; + } + + /** Sets the clock bias in seconds (-TauN). */ + @NonNull + public Builder setClockBias(@FloatRange(from = -0.002f, to = 0.002f) double clockBias) { + mClockBias = clockBias; + return this; + } + + /** Sets the frequency bias (+GammaN). */ + @NonNull + public Builder setFrequencyBias( + @FloatRange(from = -9.32e-10f, to = 9.32e-10f) double frequencyBias) { + mFrequencyBias = frequencyBias; + return this; + } + + /** Sets the frequency number. */ + @NonNull + public Builder setFrequencyNumber(@IntRange(from = -7, to = 6) int frequencyNumber) { + mFrequencyNumber = frequencyNumber; + return this; + } + + /** Builds a {@link GlonassSatelliteClockModel}. */ + @NonNull + public GlonassSatelliteClockModel build() { + return new GlonassSatelliteClockModel(this); + } + } + } + + /** + * A class contains the set of parameters needed for Glonass satellite orbit correction. + * + * <p>This is defined in RINEX 3.05 APPENDIX 10 and Glonass ICD v5.1 section 4.4. + */ + public static final class GlonassSatelliteOrbitModel implements Parcelable { + /** X position in kilometers. */ + private final double mX; + + /** X velocity in kilometers per second. */ + private final double mXDot; + + /** X acceleration in kilometers per second squared. */ + private final double mXAccel; + + /** Y position in kilometers. */ + private final double mY; + + /** Y velocity in kilometers per second. */ + private final double mYDot; + + /** Y acceleration in kilometers per second squared. */ + private final double mYAccel; + + /** Z position in kilometers. */ + private final double mZ; + + /** Z velocity in kilometers per second. */ + private final double mZDot; + + /** Z acceleration in kilometers per second squared. */ + private final double mZAccel; + + private GlonassSatelliteOrbitModel(Builder builder) { + Preconditions.checkArgumentInRange(builder.mX, -2.7e4f, 2.7e4f, "X"); + Preconditions.checkArgumentInRange(builder.mXDot, -4.3f, 4.3f, "XDot"); + Preconditions.checkArgumentInRange(builder.mXAccel, -6.2e-9f, 6.2e-9f, "XAccel"); + Preconditions.checkArgumentInRange(builder.mY, -2.7e4f, 2.7e4f, "Y"); + Preconditions.checkArgumentInRange(builder.mYDot, -4.3f, 4.3f, "YDot"); + Preconditions.checkArgumentInRange(builder.mYAccel, -6.2e-9f, 6.2e-9f, "YAccel"); + Preconditions.checkArgumentInRange(builder.mZ, -2.7e4f, 2.7e4f, "Z"); + Preconditions.checkArgumentInRange(builder.mZDot, -4.3f, 4.3f, "ZDot"); + Preconditions.checkArgumentInRange(builder.mZAccel, -6.2e-9f, 6.2e-9f, "ZAccel"); + mX = builder.mX; + mXDot = builder.mXDot; + mXAccel = builder.mXAccel; + mY = builder.mY; + mYDot = builder.mYDot; + mYAccel = builder.mYAccel; + mZ = builder.mZ; + mZDot = builder.mZDot; + mZAccel = builder.mZAccel; + } + + /** Returns the X position in kilometers. */ + @FloatRange(from = -2.7e4f, to = 2.7e4f) + public double getX() { + return mX; + } + + /** Returns the X velocity in kilometers per second. */ + @FloatRange(from = -4.3f, to = 4.3f) + public double getXDot() { + return mXDot; + } + + /** Returns the X acceleration in kilometers per second squared. */ + @FloatRange(from = -6.2e-9f, to = 6.2e-9f) + public double getXAccel() { + return mXAccel; + } + + /** Returns the Y position in kilometers. */ + @FloatRange(from = -2.7e4f, to = 2.7e4f) + public double getY() { + return mY; + } + + /** Returns the Y velocity in kilometers per second. */ + @FloatRange(from = -4.3f, to = 4.3f) + public double getYDot() { + return mYDot; + } + + /** Returns the Y acceleration in kilometers per second squared. */ + @FloatRange(from = -6.2e-9f, to = 6.2e-9f) + public double getYAccel() { + return mYAccel; + } + + /** Returns the Z position in kilometers. */ + @FloatRange(from = -2.7e4f, to = 2.7e4f) + public double getZ() { + return mZ; + } + + /** Returns the Z velocity in kilometers per second. */ + @FloatRange(from = -4.3f, to = 4.3f) + public double getZDot() { + return mZDot; + } + + /** Returns the Z acceleration in kilometers per second squared. */ + @FloatRange(from = -6.2e-9f, to = 6.2e-9f) + public double getZAccel() { + return mZAccel; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeDouble(mX); + dest.writeDouble(mXDot); + dest.writeDouble(mXAccel); + dest.writeDouble(mY); + dest.writeDouble(mYDot); + dest.writeDouble(mYAccel); + dest.writeDouble(mZ); + dest.writeDouble(mZDot); + dest.writeDouble(mZAccel); + } + + public static final @NonNull Parcelable.Creator<GlonassSatelliteOrbitModel> CREATOR = + new Parcelable.Creator<GlonassSatelliteOrbitModel>() { + @Override + public GlonassSatelliteOrbitModel createFromParcel(@NonNull Parcel source) { + return new GlonassSatelliteOrbitModel.Builder() + .setX(source.readDouble()) + .setXDot(source.readDouble()) + .setXAccel(source.readDouble()) + .setY(source.readDouble()) + .setYDot(source.readDouble()) + .setYAccel(source.readDouble()) + .setZ(source.readDouble()) + .setZDot(source.readDouble()) + .setZAccel(source.readDouble()) + .build(); + } + + @Override + public GlonassSatelliteOrbitModel[] newArray(int size) { + return new GlonassSatelliteOrbitModel[size]; + } + }; + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GlonassSatelliteOrbitModel["); + builder.append("x = ").append(mX); + builder.append(", xDot = ").append(mXDot); + builder.append(", xAccel = ").append(mXAccel); + builder.append(", y = ").append(mY); + builder.append(", yDot = ").append(mYDot); + builder.append(", yAccel = ").append(mYAccel); + builder.append(", z = ").append(mZ); + builder.append(", zDot = ").append(mZDot); + builder.append(", zAccel = ").append(mZAccel); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GlonassSatelliteOrbitModel}. */ + public static final class Builder { + private double mX; + private double mXDot; + private double mXAccel; + private double mY; + private double mYDot; + private double mYAccel; + private double mZ; + private double mZDot; + private double mZAccel; + + /** Sets the X position in kilometers. */ + @NonNull + public Builder setX(@FloatRange(from = -2.7e4f, to = 2.7e4f) double x) { + mX = x; + return this; + } + + /** Sets the X velocity in kilometers per second. */ + @NonNull + public Builder setXDot(@FloatRange(from = -4.3f, to = 4.3f) double xDot) { + mXDot = xDot; + return this; + } + + /** Sets the X acceleration in kilometers per second squared. */ + @NonNull + public Builder setXAccel(@FloatRange(from = -6.2e-9f, to = 6.2e-9f) double xAccel) { + mXAccel = xAccel; + return this; + } + + /** Sets the Y position in kilometers. */ + @NonNull + public Builder setY(@FloatRange(from = -2.7e4f, to = 2.7e4f) double y) { + mY = y; + return this; + } + + /** Sets the Y velocity in kilometers per second. */ + @NonNull + public Builder setYDot(@FloatRange(from = -4.3f, to = 4.3f) double yDot) { + mYDot = yDot; + return this; + } + + /** Sets the Y acceleration in kilometers per second squared. */ + @NonNull + public Builder setYAccel(@FloatRange(from = -6.2e-9f, to = 6.2e-9f) double yAccel) { + mYAccel = yAccel; + return this; + } + + /** Sets the Z position in kilometers. */ + @NonNull + public Builder setZ(@FloatRange(from = -2.7e4f, to = 2.7e4f) double z) { + mZ = z; + return this; + } + + /** Sets the Z velocity in kilometers per second. */ + @NonNull + public Builder setZDot(@FloatRange(from = -4.3f, to = 4.3f) double zDot) { + mZDot = zDot; + return this; + } + + /** Sets the Z acceleration in kilometers per second squared. */ + @NonNull + public Builder setZAccel(@FloatRange(from = -6.2e-9f, to = 6.2e-9f) double zAccel) { + mZAccel = zAccel; + return this; + } + + /** Builds a {@link GlonassSatelliteOrbitModel}. */ + @NonNull + public GlonassSatelliteOrbitModel build() { + return new GlonassSatelliteOrbitModel(this); + } + } + } +} diff --git a/location/java/android/location/GnssAlmanac.java b/location/java/android/location/GnssAlmanac.java new file mode 100644 index 000000000000..6466e45a965e --- /dev/null +++ b/location/java/android/location/GnssAlmanac.java @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains almanac parameters for GPS, QZSS, Galileo, Beidou. + * + * <p>For Beidou, this is defined in BDS-SIS-ICD-B1I-3.0 section 5.2.4.15. + * + * <p>For GPS, this is defined in IS-GPS-200 section 20.3.3.5.1.2. + * + * <p>For QZSS, this is defined in IS-QZSS-PNT section 4.1.2.6. + * + * <p>For Galileo, this is defined in Galileo-OS-SIS-ICD-v2.1 section 5.1.10. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GnssAlmanac implements Parcelable { + /** + * Almanac issue date in milliseconds (UTC). + * + * <p>This is unused for GPS/QZSS/Baidou. + */ + private final long mIssueDateMillis; + + /** + * Almanac issue of data. + * + * <p>This is unused for GPS/QZSS/Baidou. + */ + private final int mIod; + + /** + * Almanac reference week number. + * + * <p>For GPS and QZSS, this is GPS week number (modulo 1024). + * + * <p>For Beidou, this is Baidou week number (modulo 8192). + * + * <p>For Galileo, this is modulo 4 representation of the Galileo week number. + */ + private final int mWeekNumber; + + /** Almanac reference time in seconds. */ + private final int mToaSeconds; + + /** The list of GnssSatelliteAlmanacs. */ + @NonNull private final List<GnssSatelliteAlmanac> mGnssSatelliteAlmanacs; + + private GnssAlmanac(Builder builder) { + Preconditions.checkArgument(builder.mIssueDateMillis >= 0); + Preconditions.checkArgument(builder.mIod >= 0); + Preconditions.checkArgument(builder.mWeekNumber >= 0); + Preconditions.checkArgumentInRange(builder.mToaSeconds, 0, 604800, "ToaSeconds"); + Preconditions.checkNotNull( + builder.mGnssSatelliteAlmanacs, "GnssSatelliteAlmanacs cannot be null"); + mIssueDateMillis = builder.mIssueDateMillis; + mIod = builder.mIod; + mWeekNumber = builder.mWeekNumber; + mToaSeconds = builder.mToaSeconds; + mGnssSatelliteAlmanacs = + Collections.unmodifiableList(new ArrayList<>(builder.mGnssSatelliteAlmanacs)); + } + + /** Returns the almanac issue date in milliseconds (UTC). */ + @IntRange(from = 0) + public long getIssueDateMillis() { + return mIssueDateMillis; + } + + /** Returns the almanac issue of data. */ + @IntRange(from = 0) + public int getIod() { + return mIod; + } + + /** + * Returns the almanac reference week number. + * + * <p>For GPS and QZSS, this is GPS week number (modulo 1024). + * + * <p>For Beidou, this is Baidou week number (modulo 8192). + * + * <p>For Galileo, this is modulo 4 representation of the Galileo week number. + */ + @IntRange(from = 0) + public int getWeekNumber() { + return mWeekNumber; + } + + /** Returns the almanac reference time in seconds. */ + @IntRange(from = 0, to = 604800) + public int getToaSeconds() { + return mToaSeconds; + } + + /** Returns the list of GnssSatelliteAlmanacs. */ + @NonNull + public List<GnssSatelliteAlmanac> getGnssSatelliteAlmanacs() { + return mGnssSatelliteAlmanacs; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mIssueDateMillis); + dest.writeInt(mIod); + dest.writeInt(mWeekNumber); + dest.writeInt(mToaSeconds); + dest.writeTypedList(mGnssSatelliteAlmanacs); + } + + public static final @NonNull Creator<GnssAlmanac> CREATOR = + new Creator<GnssAlmanac>() { + @Override + public GnssAlmanac createFromParcel(Parcel in) { + GnssAlmanac.Builder gnssAlmanac = new GnssAlmanac.Builder(); + gnssAlmanac.setIssueDateMillis(in.readLong()); + gnssAlmanac.setIod(in.readInt()); + gnssAlmanac.setWeekNumber(in.readInt()); + gnssAlmanac.setToaSeconds(in.readInt()); + List<GnssSatelliteAlmanac> satelliteAlmanacs = new ArrayList<>(); + in.readTypedList(satelliteAlmanacs, GnssSatelliteAlmanac.CREATOR); + gnssAlmanac.setGnssSatelliteAlmanacs(satelliteAlmanacs); + return gnssAlmanac.build(); + } + + @Override + public GnssAlmanac[] newArray(int size) { + return new GnssAlmanac[size]; + } + }; + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("GnssAlmanac["); + builder.append("issueDateMillis=").append(mIssueDateMillis); + builder.append(", iod=").append(mIod); + builder.append(", weekNumber=").append(mWeekNumber); + builder.append(", toaSeconds=").append(mToaSeconds); + builder.append(", satelliteAlmanacs=").append(mGnssSatelliteAlmanacs); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GnssAlmanac}. */ + public static final class Builder { + private long mIssueDateMillis; + private int mIod; + private int mWeekNumber; + private int mToaSeconds; + private List<GnssSatelliteAlmanac> mGnssSatelliteAlmanacs; + + /** Sets the almanac issue date in milliseconds (UTC). */ + @NonNull + public Builder setIssueDateMillis(@IntRange(from = 0) long issueDateMillis) { + mIssueDateMillis = issueDateMillis; + return this; + } + + /** Sets the almanac issue of data. */ + @NonNull + public Builder setIod(@IntRange(from = 0) int iod) { + mIod = iod; + return this; + } + + /** + * Sets the almanac reference week number. + * + * <p>For GPS and QZSS, this is GPS week number (modulo 1024). + * + * <p>For Beidou, this is Baidou week number (modulo 8192). + * + * <p>For Galileo, this is modulo 4 representation of the Galileo week number. + */ + @NonNull + public Builder setWeekNumber(@IntRange(from = 0) int weekNumber) { + mWeekNumber = weekNumber; + return this; + } + + /** Sets the almanac reference time in seconds. */ + @NonNull + public Builder setToaSeconds(@IntRange(from = 0, to = 604800) int toaSeconds) { + mToaSeconds = toaSeconds; + return this; + } + + /** Sets the list of GnssSatelliteAlmanacs. */ + @NonNull + public Builder setGnssSatelliteAlmanacs( + @NonNull List<GnssSatelliteAlmanac> gnssSatelliteAlmanacs) { + mGnssSatelliteAlmanacs = gnssSatelliteAlmanacs; + return this; + } + + /** Builds a {@link GnssAlmanac} instance as specified by this builder. */ + @NonNull + public GnssAlmanac build() { + return new GnssAlmanac(this); + } + } + + /** + * A class contains almanac parameters for GPS, QZSS, Galileo, Beidou. + * + * <p>For Beidou, this is defined in BDS-SIS-ICD-B1I-3.0 section 5.2.4.15. + * + * <p>For GPS, this is defined in IS-GPS-200 section 20.3.3.5.1.2. + * + * <p>For QZSS, this is defined in IS-QZSS-PNT section 4.1.2.6. + * + * <p>For Galileo, this is defined in Galileo-OS-SIS-ICD-v2.1 section 5.1.10. + */ + public static final class GnssSatelliteAlmanac implements Parcelable { + /** The PRN number of the GNSS satellite. */ + private final int mSvid; + + /** + * Satellite health information. + * + * <p>For GPS, this is satellite subframe 4 and 5, page 25 6-bit health code as defined in + * IS-GPS-200 Table 20-VIII expressed in integer form. + * + * <p>For QZSS, this is the 5-bit health code as defined in IS-QZSS-PNT, Table 4.1.2-5-2 + * expressed in integer form. + * + * <p>For Beidou, this is 1-bit health information. (0=healthy, 1=unhealthy). + * + * <p>For Galileo, this is 6-bit health, bit 0 and 1 is for E5a, bit 2 and 3 is for E5b, bit + * 4 and 5 is for E1b. + */ + private final int mSvHealth; + + /** Eccentricity. */ + private final double mEccentricity; + + /** + * Inclination in semi-circles. + * + * <p>For GPS and Galileo, this is the difference between the inclination angle at reference + * time and the nominal inclination in semi-circles. + * + * <p>For Beidou and QZSS, this is the inclination angle at reference time in semi-circles. + */ + private final double mInclination; + + /** Argument of perigee in semi-circles. */ + private final double mOmega; + + /** Longitude of ascending node of orbital plane at weekly epoch in semi-circles. */ + private final double mOmega0; + + /** Rate of right ascension in semi-circles per second. */ + private final double mOmegaDot; + + /** + * Square root of semi-major axis in square root of meters. + * + * <p>For Galileo, this is the difference with respect to the square root of the nominal + * semi-major axis in square root of meters. + */ + private final double mRootA; + + /** Mean anomaly at reference time in semi-circles. */ + private final double mM0; + + /** Satellite clock time bias correction coefficient in seconds. */ + private final double mAf0; + + /** Satellite clock time drift correction coefficient in seconds per second. */ + private final double mAf1; + + private GnssSatelliteAlmanac(Builder builder) { + Preconditions.checkArgument(builder.mSvid > 0); + Preconditions.checkArgument(builder.mSvHealth >= 0); + Preconditions.checkArgument(builder.mEccentricity >= 0.0f); + Preconditions.checkArgumentInRange(builder.mInclination, -1.0f, 1.0f, "Inclination"); + Preconditions.checkArgumentInRange(builder.mOmega, -1.0f, 1.0f, "Omega"); + Preconditions.checkArgumentInRange(builder.mOmega0, -1.0f, 1.0f, "Omega0"); + Preconditions.checkArgumentInRange(builder.mOmegaDot, -1.0f, 1.0f, "OmegaDot"); + Preconditions.checkArgumentInRange(builder.mRootA, 0.0f, 8192.0f, "RootA"); + Preconditions.checkArgumentInRange(builder.mM0, -1.0f, 1.0f, "M0"); + Preconditions.checkArgumentInRange(builder.mAf0, -0.0625f, 0.0625f, "Af0"); + Preconditions.checkArgumentInRange(builder.mAf1, -1.5e-8f, 1.5e-8f, "Af1"); + mSvid = builder.mSvid; + mSvHealth = builder.mSvHealth; + mEccentricity = builder.mEccentricity; + mInclination = builder.mInclination; + mOmega = builder.mOmega; + mOmega0 = builder.mOmega0; + mOmegaDot = builder.mOmegaDot; + mRootA = builder.mRootA; + mM0 = builder.mM0; + mAf0 = builder.mAf0; + mAf1 = builder.mAf1; + } + + /** Returns the PRN number of the GNSS satellite. */ + @IntRange(from = 1) + public int getSvid() { + return mSvid; + } + + /** + * Returns the satellite health information. + * + * <p>For GPS, this is satellite subframe 4 and 5, page 25 6-bit health code as defined in + * IS-GPS-200 Table 20-VIII expressed in integer form. + * + * <p>For QZSS, this is the 5-bit health code as defined in IS-QZSS-PNT, Table 4.1.2-5-2 + * expressed in integer form. + * + * <p>For Beidou, this is 1-bit health information. (0=healthy, 1=unhealthy). + * + * <p>For Galileo, this is 6-bit health, bit 0 and 1 is for E5a, bit 2 and 3 is for E5b, + * bit 4 and 5 is for E1b. + */ + @IntRange(from = 0) + public int getSvHealth() { + return mSvHealth; + } + + /** Returns the eccentricity. */ + @FloatRange(from = 0.0f) + public double getEccentricity() { + return mEccentricity; + } + + /** + * Returns the inclination in semi-circles. + * + * <p>For GPS and Galileo, this is the difference between the inclination angle at reference + * time and the nominal inclination in semi-circles. + * + * <p>For Beidou and QZSS, this is the inclination angle at reference time in semi-circles. + */ + @FloatRange(from = -1.0f, to = 1.0f) + public double getInclination() { + return mInclination; + } + + /** Returns the argument of perigee in semi-circles. */ + @FloatRange(from = -1.0f, to = 1.0f) + public double getOmega() { + return mOmega; + } + + /** + * Returns the longitude of ascending node of orbital plane at weekly epoch in semi-circles. + */ + @FloatRange(from = -1.0f, to = 1.0f) + public double getOmega0() { + return mOmega0; + } + + /** Returns the rate of right ascension in semi-circles per second. */ + @FloatRange(from = -1.0f, to = 1.0f) + public double getOmegaDot() { + return mOmegaDot; + } + + /** + * Returns the square root of semi-major axis in square root of meters. + * + * <p>For Galileo, this is the difference with respect to the square root of the nominal + * semi-major axis in square root of meters. + */ + @FloatRange(from = 0.0f, to = 8192.0f) + public double getRootA() { + return mRootA; + } + + /** Returns the mean anomaly at reference time in semi-circles. */ + @FloatRange(from = -1.0f, to = 1.0f) + public double getM0() { + return mM0; + } + + /** Returns the satellite clock time bias correction coefficient in seconds. */ + @FloatRange(from = -0.0625f, to = 0.0625f) + public double getAf0() { + return mAf0; + } + + /** Returns the satellite clock time drift correction coefficient in seconds per second. */ + @FloatRange(from = -1.5e-8f, to = 1.5e-8f) + public double getAf1() { + return mAf1; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSvid); + dest.writeInt(mSvHealth); + dest.writeDouble(mEccentricity); + dest.writeDouble(mInclination); + dest.writeDouble(mOmega); + dest.writeDouble(mOmega0); + dest.writeDouble(mOmegaDot); + dest.writeDouble(mRootA); + dest.writeDouble(mM0); + dest.writeDouble(mAf0); + dest.writeDouble(mAf1); + } + + public static final @NonNull Creator<GnssSatelliteAlmanac> CREATOR = + new Creator<GnssSatelliteAlmanac>() { + @Override + public GnssSatelliteAlmanac createFromParcel(Parcel in) { + return new GnssSatelliteAlmanac( + new Builder() + .setSvid(in.readInt()) + .setSvHealth(in.readInt()) + .setEccentricity(in.readDouble()) + .setInclination(in.readDouble()) + .setOmega(in.readDouble()) + .setOmega0(in.readDouble()) + .setOmegaDot(in.readDouble()) + .setRootA(in.readDouble()) + .setM0(in.readDouble()) + .setAf0(in.readDouble()) + .setAf1(in.readDouble())); + } + + @Override + public GnssSatelliteAlmanac[] newArray(int size) { + return new GnssSatelliteAlmanac[size]; + } + }; + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GnssSatelliteAlmanac["); + builder.append("svid = ").append(mSvid); + builder.append(", svHealth = ").append(mSvHealth); + builder.append(", eccentricity = ").append(mEccentricity); + builder.append(", inclination = ").append(mInclination); + builder.append(", omega = ").append(mOmega); + builder.append(", omega0 = ").append(mOmega0); + builder.append(", omegaDot = ").append(mOmegaDot); + builder.append(", rootA = ").append(mRootA); + builder.append(", m0 = ").append(mM0); + builder.append(", af0 = ").append(mAf0); + builder.append(", af1 = ").append(mAf1); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GnssSatelliteAlmanac}. */ + public static final class Builder { + private int mSvid; + private int mSvHealth; + private double mEccentricity; + private double mInclination; + private double mOmega; + private double mOmega0; + private double mOmegaDot; + private double mRootA; + private double mM0; + private double mAf0; + private double mAf1; + + /** Sets the PRN number of the GNSS satellite. */ + @NonNull + public Builder setSvid(@IntRange(from = 1) int svid) { + mSvid = svid; + return this; + } + + /** + * Sets the satellite health information. + * + * <p>For GPS, this is satellite subframe 4 and 5, page 25 6-bit health code as defined + * in IS-GPS-200 Table 20-VIII expressed in integer form. + * + * <p>For QZSS, this is the 5-bit health code as defined in IS-QZSS-PNT, Table 4.1.2-5-2 + * expressed in integer form. + * + * <p>For Beidou, this is 1-bit health information. (0=healthy, 1=unhealthy). + * + * <p>For Galileo, this is 6-bit health, bit 0 and 1 is for E5a, + * bit 2 and 3 is for E5b, bit 4 and 5 is for E1b. + */ + @NonNull + public Builder setSvHealth(@IntRange(from = 0) int svHealth) { + mSvHealth = svHealth; + return this; + } + + /** Sets the eccentricity. */ + @NonNull + public Builder setEccentricity(@FloatRange(from = 0.0f) double eccentricity) { + mEccentricity = eccentricity; + return this; + } + + /** + * Sets the inclination in semi-circles. + * + * <p>For GPS and Galileo, this is the difference between the inclination angle at + * reference time and the nominal inclination in semi-circles. + * + * <p>For Beidou and QZSS, this is the inclination angle at reference time in + * semi-circles. + */ + @NonNull + public Builder setInclination(@FloatRange(from = -1.0f, to = 1.0f) double inclination) { + mInclination = inclination; + return this; + } + + /** Sets the argument of perigee in semi-circles. */ + @NonNull + public Builder setOmega(@FloatRange(from = -1.0f, to = 1.0f) double omega) { + mOmega = omega; + return this; + } + + /** + * Sets the longitude of ascending node of orbital plane at weekly epoch in + * semi-circles. + */ + @NonNull + public Builder setOmega0(@FloatRange(from = -1.0f, to = 1.0f) double omega0) { + mOmega0 = omega0; + return this; + } + + /** Sets the rate of right ascension in semi-circles per second. */ + @NonNull + public Builder setOmegaDot(@FloatRange(from = -1.0f, to = 1.0f) double omegaDot) { + mOmegaDot = omegaDot; + return this; + } + + /** + * Sets the square root of semi-major axis in square root of meters. + * + * <p>For Galileo, this is the difference with respect to the square root of the nominal + * semi-major axis in square root of meters. + */ + @NonNull + public Builder setRootA(@FloatRange(from = 0.0f, to = 8192.0f) double rootA) { + mRootA = rootA; + return this; + } + + /** Sets the mean anomaly at reference time in semi-circles. */ + @NonNull + public Builder setM0(@FloatRange(from = -1.0f, to = 1.0f) double m0) { + mM0 = m0; + return this; + } + + /** Sets the satellite clock time bias correction coefficient in seconds. */ + @NonNull + public Builder setAf0(@FloatRange(from = -0.0625f, to = 0.0625f) double af0) { + mAf0 = af0; + return this; + } + + /** Sets the satellite clock time drift correction coefficient in seconds per second. */ + @NonNull + public Builder setAf1(@FloatRange(from = -1.5e-8f, to = 1.5e-8f) double af1) { + mAf1 = af1; + return this; + } + + /** Builds a {@link GnssSatelliteAlmanac} instance as specified by this builder. */ + @NonNull + public GnssSatelliteAlmanac build() { + return new GnssSatelliteAlmanac(this); + } + } + } +} diff --git a/location/java/android/location/GnssAssistance.aidl b/location/java/android/location/GnssAssistance.aidl new file mode 100644 index 000000000000..2745683ec330 --- /dev/null +++ b/location/java/android/location/GnssAssistance.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +parcelable GnssAssistance;
\ No newline at end of file diff --git a/location/java/android/location/GnssAssistance.java b/location/java/android/location/GnssAssistance.java new file mode 100644 index 000000000000..e941122f8c79 --- /dev/null +++ b/location/java/android/location/GnssAssistance.java @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains GNSS assistance. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GnssAssistance implements Parcelable { + + /** GPS assistance. */ + @Nullable private final GpsAssistance mGpsAssistance; + + /** Glonass assistance. */ + @Nullable private final GlonassAssistance mGlonassAssistance; + + /** Galileo assistance. */ + @Nullable private final GalileoAssistance mGalileoAssistance; + + /** Beidou assistance. */ + @Nullable private final BeidouAssistance mBeidouAssistance; + + /** QZSS assistance. */ + @Nullable private final QzssAssistance mQzssAssistance; + + private GnssAssistance(Builder builder) { + mGpsAssistance = builder.mGpsAssistance; + mGlonassAssistance = builder.mGlonassAssistance; + mGalileoAssistance = builder.mGalileoAssistance; + mBeidouAssistance = builder.mBeidouAssistance; + mQzssAssistance = builder.mQzssAssistance; + } + + /** Returns the GPS assistance. */ + @Nullable + public GpsAssistance getGpsAssistance() { + return mGpsAssistance; + } + + /** Returns the Glonass assistance. */ + @Nullable + public GlonassAssistance getGlonassAssistance() { + return mGlonassAssistance; + } + + /** Returns the Galileo assistance. */ + @Nullable + public GalileoAssistance getGalileoAssistance() { + return mGalileoAssistance; + } + + /** Returns the Beidou assistance. */ + @Nullable + public BeidouAssistance getBeidouAssistance() { + return mBeidouAssistance; + } + + /** Returns the Qzss assistance. */ + @Nullable + public QzssAssistance getQzssAssistance() { + return mQzssAssistance; + } + + public static final @NonNull Creator<GnssAssistance> CREATOR = + new Creator<GnssAssistance>() { + @Override + @NonNull + public GnssAssistance createFromParcel(Parcel in) { + return new GnssAssistance.Builder() + .setGpsAssistance(in.readTypedObject(GpsAssistance.CREATOR)) + .setGlonassAssistance(in.readTypedObject(GlonassAssistance.CREATOR)) + .setGalileoAssistance(in.readTypedObject(GalileoAssistance.CREATOR)) + .setBeidouAssistance(in.readTypedObject(BeidouAssistance.CREATOR)) + .setQzssAssistance(in.readTypedObject(QzssAssistance.CREATOR)) + .build(); + } + + @Override + public GnssAssistance[] newArray(int size) { + return new GnssAssistance[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeTypedObject(mGpsAssistance, flags); + parcel.writeTypedObject(mGlonassAssistance, flags); + parcel.writeTypedObject(mGalileoAssistance, flags); + parcel.writeTypedObject(mBeidouAssistance, flags); + parcel.writeTypedObject(mQzssAssistance, flags); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GnssAssistance["); + builder.append("gpsAssistance = ").append(mGpsAssistance); + builder.append(", glonassAssistance = ").append(mGlonassAssistance); + builder.append(", galileoAssistance = ").append(mGalileoAssistance); + builder.append(", beidouAssistance = ").append(mBeidouAssistance); + builder.append(", qzssAssistance = ").append(mQzssAssistance); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GnssAssistance}. */ + public static final class Builder { + private GpsAssistance mGpsAssistance; + private GlonassAssistance mGlonassAssistance; + private GalileoAssistance mGalileoAssistance; + private BeidouAssistance mBeidouAssistance; + private QzssAssistance mQzssAssistance; + + /** Sets the GPS assistance. */ + @NonNull + public Builder setGpsAssistance(@Nullable GpsAssistance gpsAssistance) { + mGpsAssistance = gpsAssistance; + return this; + } + + /** Sets the Glonass assistance. */ + @NonNull + public Builder setGlonassAssistance(@Nullable GlonassAssistance glonassAssistance) { + mGlonassAssistance = glonassAssistance; + return this; + } + + /** Sets the Galileo assistance. */ + @NonNull + public Builder setGalileoAssistance(@Nullable GalileoAssistance galileoAssistance) { + mGalileoAssistance = galileoAssistance; + return this; + } + + /** Sets the Beidou assistance. */ + @NonNull + public Builder setBeidouAssistance(@Nullable BeidouAssistance beidouAssistance) { + mBeidouAssistance = beidouAssistance; + return this; + } + + /** Sets the QZSS assistance. */ + @NonNull + public Builder setQzssAssistance(@Nullable QzssAssistance qzssAssistance) { + mQzssAssistance = qzssAssistance; + return this; + } + + /** Builds a {@link GnssAssistance} instance as specified by this builder. */ + @NonNull + public GnssAssistance build() { + return new GnssAssistance(this); + } + } + + /** A class contains GNSS corrections for satellites. */ + public static final class GnssSatelliteCorrections implements Parcelable { + /** + * Pseudo-random or satellite ID number for the satellite, a.k.a. Space Vehicle (SV), or OSN + * number for Glonass. + * + * <p>The distinction is made by looking at the constellation field. Values must be in the + * range of: + * + * <p>- GPS: 1-32 + * + * <p>- GLONASS: 1-25 + * + * <p>- QZSS: 183-206 + * + * <p>- Galileo: 1-36 + * + * <p>- Beidou: 1-63 + */ + @IntRange(from = 1, to = 206) + int mSvid; + + /** List of Ionospheric corrections */ + @NonNull List<IonosphericCorrection> mIonosphericCorrections; + + /** + * Creates a new {@link GnssSatelliteCorrections} instance. + * + * @param svid The Pseudo-random or satellite ID number for the satellite, a.k.a. Space + * Vehicle (SV), or OSN number for Glonass. + * <p>The distinction is made by looking at the constellation field. Values must be in + * the range of: + * <p>- GPS: 1-32 + * <p>- GLONASS: 1-25 + * <p>- QZSS: 183-206 + * <p>- Galileo: 1-36 + * <p>- Beidou: 1-63 + * @param ionosphericCorrections The list of Ionospheric corrections. + */ + public GnssSatelliteCorrections( + @IntRange(from = 1, to = 206) int svid, + @NonNull final List<IonosphericCorrection> ionosphericCorrections) { + // Allow SV ID beyond the range to support potential future extensibility. + Preconditions.checkArgument(svid >= 1); + Preconditions.checkNotNull( + ionosphericCorrections, "IonosphericCorrections cannot be null"); + mSvid = svid; + mIonosphericCorrections = + Collections.unmodifiableList(new ArrayList<>(ionosphericCorrections)); + } + + /** + * Returns the Pseudo-random or satellite ID number for the satellite, a.k.a. Space Vehicle + * (SV), or OSN number for Glonass. + * + * <p>The distinction is made by looking at the constellation field. Values must be in the + * range of: + * + * <p>- GPS: 1-32 + * + * <p>- GLONASS: 1-25 + * + * <p>- QZSS: 183-206 + * + * <p>- Galileo: 1-36 + * + * <p>- Beidou: 1-63 + */ + @IntRange(from = 1, to = 206) + public int getSvid() { + return mSvid; + } + + /** Returns the list of Ionospheric corrections. */ + @NonNull + public List<IonosphericCorrection> getIonosphericCorrections() { + return mIonosphericCorrections; + } + + public static final @NonNull Creator<GnssSatelliteCorrections> CREATOR = + new Creator<GnssSatelliteCorrections>() { + @Override + @NonNull + public GnssSatelliteCorrections createFromParcel(Parcel in) { + int svid = in.readInt(); + List<IonosphericCorrection> ionosphericCorrections = new ArrayList<>(); + in.readTypedList(ionosphericCorrections, IonosphericCorrection.CREATOR); + return new GnssSatelliteCorrections(svid, ionosphericCorrections); + } + + @Override + public GnssSatelliteCorrections[] newArray(int size) { + return new GnssSatelliteCorrections[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mSvid); + parcel.writeTypedList(mIonosphericCorrections, flags); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GnssSatelliteCorrections["); + builder.append("svid = ").append(mSvid); + builder.append(", ionosphericCorrections = ").append(mIonosphericCorrections); + builder.append("]"); + return builder.toString(); + } + } +} diff --git a/location/java/android/location/GnssCorrectionComponent.java b/location/java/android/location/GnssCorrectionComponent.java new file mode 100644 index 000000000000..f55dde1c9228 --- /dev/null +++ b/location/java/android/location/GnssCorrectionComponent.java @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class that contains Gnss correction associated with a component (e.g. the Ionospheric error). + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GnssCorrectionComponent implements Parcelable { + /** + * Uniquely identifies the source of correction (e.g. "Klobuchar" for ionospheric corrections). + * Clients should not depend on the value of the source key but, rather, can compare + * before/after to detect changes. + */ + @NonNull private final String mSourceKey; + + /** The correction is only applicable during this time interval. */ + @NonNull private final GnssInterval mValidityInterval; + + /** Pseudorange correction. */ + @NonNull private final PseudorangeCorrection mPseudorangeCorrection; + + /** + * Creates a GnssCorrectionComponent. + * + * @param sourceKey Uniquely identifies the source of correction (e.g. "Klobuchar" for + * ionospheric corrections). Clients should not depend on the value of the source key but, + * rather, can compare before/after to detect changes. + * @param validityInterval The correction is only applicable during this time interval. + * @param pseudorangeCorrection Pseudorange correction. + */ + public GnssCorrectionComponent( + @NonNull String sourceKey, + @NonNull GnssInterval validityInterval, + @NonNull PseudorangeCorrection pseudorangeCorrection) { + Preconditions.checkNotNull(sourceKey, "SourceKey cannot be null"); + Preconditions.checkNotNull(validityInterval, "ValidityInterval cannot be null"); + Preconditions.checkNotNull(pseudorangeCorrection, "PseudorangeCorrection cannot be null"); + mSourceKey = sourceKey; + mValidityInterval = validityInterval; + mPseudorangeCorrection = pseudorangeCorrection; + } + + /** Returns the source key of the correction. */ + @NonNull + public String getSourceKey() { + return mSourceKey; + } + + /** Returns the validity interval of the correction. */ + @NonNull + public GnssInterval getValidityInterval() { + return mValidityInterval; + } + + /** Returns the pseudorange correction. */ + @NonNull + public PseudorangeCorrection getPseudorangeCorrection() { + return mPseudorangeCorrection; + } + + public static final @NonNull Creator<GnssCorrectionComponent> CREATOR = + new Creator<GnssCorrectionComponent>() { + @Override + @NonNull + public GnssCorrectionComponent createFromParcel(Parcel in) { + String sourceKey = in.readString8(); + GnssInterval validityInterval = in.readTypedObject(GnssInterval.CREATOR); + PseudorangeCorrection pseudorangeCorrection = + in.readTypedObject(PseudorangeCorrection.CREATOR); + return new GnssCorrectionComponent( + sourceKey, validityInterval, pseudorangeCorrection); + } + + @Override + public GnssCorrectionComponent[] newArray(int size) { + return new GnssCorrectionComponent[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString8(mSourceKey); + dest.writeTypedObject(mValidityInterval, flags); + dest.writeTypedObject(mPseudorangeCorrection, flags); + } + + /** + * Time interval referenced against the GPS epoch. The start must be less than or equal to the + * end. When the start equals the end, the interval is empty. + */ + public static final class GnssInterval implements Parcelable { + /** + * Inclusive start of the interval in milliseconds since the GPS epoch. A timestamp matching + * this interval will have to be the same or after the start. Required as a reference time + * for the initial correction value and its rate of change over time. + */ + private final long mStartMillisSinceGpsEpoch; + + /** + * Exclusive end of the interval in milliseconds since the GPS epoch. If specified, a + * timestamp matching this interval will have to be before the end. + */ + private final long mEndMillisSinceGpsEpoch; + + /** + * Creates a GnssInterval. + * + * @param startMillisSinceGpsEpoch Inclusive start of the interval in milliseconds since the + * GPS epoch. A timestamp matching this interval will have to be the same or after the + * start. Required as a reference time for the initial correction value and its rate of + * change over time. + * @param endMillisSinceGpsEpoch Exclusive end of the interval in milliseconds since the GPS + * epoch. If specified, a timestamp matching this interval will have to be before the + * end. + */ + public GnssInterval( + @IntRange(from = 0) long startMillisSinceGpsEpoch, + @IntRange(from = 0) long endMillisSinceGpsEpoch) { + Preconditions.checkArgument(startMillisSinceGpsEpoch >= 0); + Preconditions.checkArgument(endMillisSinceGpsEpoch >= 0); + mStartMillisSinceGpsEpoch = startMillisSinceGpsEpoch; + mEndMillisSinceGpsEpoch = endMillisSinceGpsEpoch; + } + + /** Returns the inclusive start of the interval in milliseconds since the GPS epoch. */ + @IntRange(from = 0) + public long getStartMillisSinceGpsEpoch() { + return mStartMillisSinceGpsEpoch; + } + + /** Returns the exclusive end of the interval in milliseconds since the GPS epoch. */ + @IntRange(from = 0) + public long getEndMillisSinceGpsEpoch() { + return mEndMillisSinceGpsEpoch; + } + + public static final @NonNull Creator<GnssInterval> CREATOR = + new Creator<GnssInterval>() { + @Override + @NonNull + public GnssInterval createFromParcel(Parcel in) { + return new GnssInterval(in.readLong(), in.readLong()); + } + + @Override + public GnssInterval[] newArray(int size) { + return new GnssInterval[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeLong(mStartMillisSinceGpsEpoch); + parcel.writeLong(mEndMillisSinceGpsEpoch); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GnssInterval["); + builder.append("startMillisSinceGpsEpoch = ").append(mStartMillisSinceGpsEpoch); + builder.append(", endMillisSinceGpsEpoch = ").append(mEndMillisSinceGpsEpoch); + builder.append("]"); + return builder.toString(); + } + } + + /** Pseudorange correction. */ + public static final class PseudorangeCorrection implements Parcelable { + + /** Correction to be added to the measured pseudorange, in meters. */ + private final double mCorrectionMeters; + + /** Uncertainty of the correction, in meters. */ + private final double mCorrectionUncertaintyMeters; + + /** + * Linear approximation of the change in correction over time. Intended usage is to adjust + * the correction using the formula: correctionMeters + correctionRateMetersPerSecond * + * delta_seconds Where `delta_seconds` is the number of elapsed seconds since the beginning + * of the correction validity interval. + */ + private final double mCorrectionRateMetersPerSecond; + + /** + * Creates a PseudorangeCorrection. + * + * @param correctionMeters Correction to be added to the measured pseudorange, in meters. + * @param correctionUncertaintyMeters Uncertainty of the correction, in meters. + * @param correctionRateMetersPerSecond Linear approximation of the change in correction + * over time. Intended usage is to adjust the correction using the formula: + * correctionMeters + correctionRateMetersPerSecond * delta_seconds Where + * `delta_seconds` is the number of elapsed seconds since the beginning of the + * correction validity interval. + */ + public PseudorangeCorrection( + double correctionMeters, + double correctionUncertaintyMeters, + double correctionRateMetersPerSecond) { + Preconditions.checkArgument(correctionUncertaintyMeters >= 0); + mCorrectionMeters = correctionMeters; + mCorrectionUncertaintyMeters = correctionUncertaintyMeters; + mCorrectionRateMetersPerSecond = correctionRateMetersPerSecond; + } + + /** Returns the correction to be added to the measured pseudorange, in meters. */ + public double getCorrectionMeters() { + return mCorrectionMeters; + } + + /** Returns the uncertainty of the correction, in meters. */ + @FloatRange(from = 0.0f) + public double getCorrectionUncertaintyMeters() { + return mCorrectionUncertaintyMeters; + } + + /** Returns the linear approximation of the change in correction over time. */ + public double getCorrectionRateMetersPerSecond() { + return mCorrectionRateMetersPerSecond; + } + + public static final @NonNull Creator<PseudorangeCorrection> CREATOR = + new Creator<PseudorangeCorrection>() { + @Override + @NonNull + public PseudorangeCorrection createFromParcel(Parcel in) { + return new PseudorangeCorrection( + in.readDouble(), in.readDouble(), in.readDouble()); + } + + @Override + public PseudorangeCorrection[] newArray(int size) { + return new PseudorangeCorrection[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeDouble(mCorrectionMeters); + parcel.writeDouble(mCorrectionUncertaintyMeters); + parcel.writeDouble(mCorrectionRateMetersPerSecond); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("PseudorangeCorrection["); + builder.append("correctionMeters = ").append(mCorrectionMeters); + builder.append(", correctionUncertaintyMeters = ").append(mCorrectionUncertaintyMeters); + builder.append(", correctionRateMetersPerSecond = ") + .append(mCorrectionRateMetersPerSecond); + builder.append("]"); + return builder.toString(); + } + } +} diff --git a/location/java/android/location/GpsAssistance.java b/location/java/android/location/GpsAssistance.java new file mode 100644 index 000000000000..5202fc4cd851 --- /dev/null +++ b/location/java/android/location/GpsAssistance.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.location.GnssAssistance.GnssSatelliteCorrections; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains GPS assistance. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GpsAssistance implements Parcelable { + + /** The GPS almanac. */ + @Nullable private final GnssAlmanac mAlmanac; + + /** The Klobuchar ionospheric model. */ + @Nullable private final KlobucharIonosphericModel mIonosphericModel; + + /** The UTC model. */ + @Nullable private final UtcModel mUtcModel; + + /** The leap seconds model. */ + @Nullable private final LeapSecondsModel mLeapSecondsModel; + + /** The list of time models. */ + @NonNull private final List<TimeModel> mTimeModels; + + /** The list of GPS ephemeris. */ + @NonNull private final List<GpsSatelliteEphemeris> mSatelliteEphemeris; + + /** The list of real time integrity models. */ + @NonNull private final List<RealTimeIntegrityModel> mRealTimeIntegrityModels; + + /** The list of GPS satellite corrections. */ + @NonNull private final List<GnssSatelliteCorrections> mSatelliteCorrections; + + private GpsAssistance(Builder builder) { + mAlmanac = builder.mAlmanac; + mIonosphericModel = builder.mIonosphericModel; + mUtcModel = builder.mUtcModel; + mLeapSecondsModel = builder.mLeapSecondsModel; + if (builder.mTimeModels != null) { + mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); + } else { + mTimeModels = new ArrayList<>(); + } + if (builder.mSatelliteEphemeris != null) { + mSatelliteEphemeris = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteEphemeris)); + } else { + mSatelliteEphemeris = new ArrayList<>(); + } + if (builder.mRealTimeIntegrityModels != null) { + mRealTimeIntegrityModels = + Collections.unmodifiableList(new ArrayList<>(builder.mRealTimeIntegrityModels)); + } else { + mRealTimeIntegrityModels = new ArrayList<>(); + } + if (builder.mSatelliteCorrections != null) { + mSatelliteCorrections = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteCorrections)); + } else { + mSatelliteCorrections = new ArrayList<>(); + } + } + + /** Returns the GPS almanac. */ + @Nullable + public GnssAlmanac getAlmanac() { + return mAlmanac; + } + + /** Returns the Klobuchar ionospheric model. */ + @Nullable + public KlobucharIonosphericModel getIonosphericModel() { + return mIonosphericModel; + } + + /** Returns the UTC model. */ + @Nullable + public UtcModel getUtcModel() { + return mUtcModel; + } + + /** Returns the leap seconds model. */ + @Nullable + public LeapSecondsModel getLeapSecondsModel() { + return mLeapSecondsModel; + } + + /** Returns the list of time models. */ + @NonNull + public List<TimeModel> getTimeModels() { + return mTimeModels; + } + + /** Returns the list of GPS ephemeris. */ + @NonNull + public List<GpsSatelliteEphemeris> getSatelliteEphemeris() { + return mSatelliteEphemeris; + } + + /** Returns the list of real time integrity models. */ + @NonNull + public List<RealTimeIntegrityModel> getRealTimeIntegrityModels() { + return mRealTimeIntegrityModels; + } + + /** Returns the list of GPS satellite corrections. */ + @NonNull + public List<GnssSatelliteCorrections> getSatelliteCorrections() { + return mSatelliteCorrections; + } + + public static final @NonNull Creator<GpsAssistance> CREATOR = + new Creator<GpsAssistance>() { + @Override + @NonNull + public GpsAssistance createFromParcel(Parcel in) { + return new GpsAssistance.Builder() + .setAlmanac(in.readTypedObject(GnssAlmanac.CREATOR)) + .setIonosphericModel( + in.readTypedObject(KlobucharIonosphericModel.CREATOR)) + .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) + .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) + .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) + .setSatelliteEphemeris( + in.createTypedArrayList(GpsSatelliteEphemeris.CREATOR)) + .setRealTimeIntegrityModels( + in.createTypedArrayList(RealTimeIntegrityModel.CREATOR)) + .setSatelliteCorrections( + in.createTypedArrayList(GnssSatelliteCorrections.CREATOR)) + .build(); + } + + @Override + public GpsAssistance[] newArray(int size) { + return new GpsAssistance[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mAlmanac, flags); + dest.writeTypedObject(mIonosphericModel, flags); + dest.writeTypedObject(mUtcModel, flags); + dest.writeTypedObject(mLeapSecondsModel, flags); + dest.writeTypedList(mTimeModels); + dest.writeTypedList(mSatelliteEphemeris); + dest.writeTypedList(mRealTimeIntegrityModels); + dest.writeTypedList(mSatelliteCorrections); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GnssAssistance["); + builder.append("almanac = ").append(mAlmanac); + builder.append(", ionosphericModel = ").append(mIonosphericModel); + builder.append(", utcModel = ").append(mUtcModel); + builder.append(", leapSecondsModel = ").append(mLeapSecondsModel); + builder.append(", timeModels = ").append(mTimeModels); + builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); + builder.append(", realTimeIntegrityModels = ").append(mRealTimeIntegrityModels); + builder.append(", satelliteCorrections = ").append(mSatelliteCorrections); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GpsAssistance}. */ + public static final class Builder { + private GnssAlmanac mAlmanac; + private KlobucharIonosphericModel mIonosphericModel; + private UtcModel mUtcModel; + private LeapSecondsModel mLeapSecondsModel; + private List<TimeModel> mTimeModels; + private List<GpsSatelliteEphemeris> mSatelliteEphemeris; + private List<RealTimeIntegrityModel> mRealTimeIntegrityModels; + private List<GnssSatelliteCorrections> mSatelliteCorrections; + + /** Sets the GPS almanac. */ + @NonNull + public Builder setAlmanac( + @Nullable @SuppressLint("NullableCollection") GnssAlmanac almanac) { + mAlmanac = almanac; + return this; + } + + /** Sets the Klobuchar ionospheric model. */ + @NonNull + public Builder setIonosphericModel( + @Nullable @SuppressLint("NullableCollection") + KlobucharIonosphericModel ionosphericModel) { + mIonosphericModel = ionosphericModel; + return this; + } + + /** Sets the UTC model. */ + @NonNull + public Builder setUtcModel( + @Nullable @SuppressLint("NullableCollection") UtcModel utcModel) { + mUtcModel = utcModel; + return this; + } + + /** Sets the leap seconds model. */ + @NonNull + public Builder setLeapSecondsModel( + @Nullable @SuppressLint("NullableCollection") LeapSecondsModel leapSecondsModel) { + mLeapSecondsModel = leapSecondsModel; + return this; + } + + /** Sets the list of time models. */ + @NonNull + public Builder setTimeModels( + @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + mTimeModels = timeModels; + return this; + } + + /** Sets the list of GPS ephemeris. */ + @NonNull + public Builder setSatelliteEphemeris( + @Nullable @SuppressLint("NullableCollection") + List<GpsSatelliteEphemeris> satelliteEphemeris) { + mSatelliteEphemeris = satelliteEphemeris; + return this; + } + + /** Sets the list of real time integrity models. */ + @NonNull + public Builder setRealTimeIntegrityModels( + @Nullable @SuppressLint("NullableCollection") + List<RealTimeIntegrityModel> realTimeIntegrityModels) { + mRealTimeIntegrityModels = realTimeIntegrityModels; + return this; + } + + /** Sets the list of GPS satellite corrections. */ + @NonNull + public Builder setSatelliteCorrections( + @Nullable @SuppressLint("NullableCollection") + List<GnssSatelliteCorrections> satelliteCorrections) { + mSatelliteCorrections = satelliteCorrections; + return this; + } + + /** Builds a {@link GpsAssistance} instance as specified by this builder. */ + @NonNull + public GpsAssistance build() { + return new GpsAssistance(this); + } + } +} diff --git a/location/java/android/location/GpsSatelliteEphemeris.java b/location/java/android/location/GpsSatelliteEphemeris.java new file mode 100644 index 000000000000..ec6bc59dc69c --- /dev/null +++ b/location/java/android/location/GpsSatelliteEphemeris.java @@ -0,0 +1,632 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * This class contains ephemeris parameters specific to GPS satellites. + * + * <p>This is defined in IS-GPS-200 section 20.3.3.3. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class GpsSatelliteEphemeris implements Parcelable { + /** Satellite PRN */ + private final int mPrn; + + /** L2 parameters. */ + @NonNull private final GpsL2Params mGpsL2Params; + + /** Clock model. */ + @NonNull private final GpsSatelliteClockModel mSatelliteClockModel; + + /** Orbit model. */ + @NonNull private final KeplerianOrbitModel mSatelliteOrbitModel; + + /** Satellite health. */ + @NonNull private final GpsSatelliteHealth mSatelliteHealth; + + /** Ephemeris time. */ + @NonNull private final SatelliteEphemerisTime mSatelliteEphemerisTime; + + private GpsSatelliteEphemeris(Builder builder) { + // Allow PRN beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mPrn >= 1); + Preconditions.checkNotNull(builder.mGpsL2Params, "GPSL2Params cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteClockModel, + "SatelliteClockModel cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteOrbitModel, + "SatelliteOrbitModel cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteHealth, + "SatelliteHealth cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteEphemerisTime, + "SatelliteEphemerisTime cannot be null"); + mPrn = builder.mPrn; + mGpsL2Params = builder.mGpsL2Params; + mSatelliteClockModel = builder.mSatelliteClockModel; + mSatelliteOrbitModel = builder.mSatelliteOrbitModel; + mSatelliteHealth = builder.mSatelliteHealth; + mSatelliteEphemerisTime = builder.mSatelliteEphemerisTime; + } + + /** Returns the PRN of the satellite. */ + @IntRange(from = 1, to = 32) + public int getPrn() { + return mPrn; + } + + /** Returns the L2 parameters of the satellite. */ + @NonNull + public GpsL2Params getGpsL2Params() { + return mGpsL2Params; + } + + /** Returns the clock model of the satellite. */ + @NonNull + public GpsSatelliteClockModel getSatelliteClockModel() { + return mSatelliteClockModel; + } + + /** Returns the orbit model of the satellite. */ + @NonNull + public KeplerianOrbitModel getSatelliteOrbitModel() { + return mSatelliteOrbitModel; + } + + /** Returns the satellite health. */ + @NonNull + public GpsSatelliteHealth getSatelliteHealth() { + return mSatelliteHealth; + } + + /** Returns the ephemeris time. */ + @NonNull + public SatelliteEphemerisTime getSatelliteEphemerisTime() { + return mSatelliteEphemerisTime; + } + + public static final @NonNull Creator<GpsSatelliteEphemeris> CREATOR = + new Creator<GpsSatelliteEphemeris>() { + @Override + @NonNull + public GpsSatelliteEphemeris createFromParcel(Parcel in) { + final GpsSatelliteEphemeris.Builder gpsSatelliteEphemeris = + new Builder() + .setPrn(in.readInt()) + .setGpsL2Params(in.readTypedObject(GpsL2Params.CREATOR)) + .setSatelliteClockModel( + in.readTypedObject(GpsSatelliteClockModel.CREATOR)) + .setSatelliteOrbitModel( + in.readTypedObject(KeplerianOrbitModel.CREATOR)) + .setSatelliteHealth( + in.readTypedObject(GpsSatelliteHealth.CREATOR)) + .setSatelliteEphemerisTime( + in.readTypedObject(SatelliteEphemerisTime.CREATOR)); + return gpsSatelliteEphemeris.build(); + } + + @Override + public GpsSatelliteEphemeris[] newArray(int size) { + return new GpsSatelliteEphemeris[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mPrn); + parcel.writeTypedObject(mGpsL2Params, flags); + parcel.writeTypedObject(mSatelliteClockModel, flags); + parcel.writeTypedObject(mSatelliteOrbitModel, flags); + parcel.writeTypedObject(mSatelliteHealth, flags); + parcel.writeTypedObject(mSatelliteEphemerisTime, flags); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GpsSatelliteEphemeris["); + builder.append("prn = ").append(mPrn); + builder.append(", gpsL2Params = ").append(mGpsL2Params); + builder.append(", satelliteClockModel = ").append(mSatelliteClockModel); + builder.append(", satelliteOrbitModel = ").append(mSatelliteOrbitModel); + builder.append(", satelliteHealth = ").append(mSatelliteHealth); + builder.append(", satelliteEphemerisTime = ").append(mSatelliteEphemerisTime); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GpsSatelliteEphemeris} */ + public static final class Builder { + private int mPrn = 0; + private GpsL2Params mGpsL2Params; + private GpsSatelliteClockModel mSatelliteClockModel; + private KeplerianOrbitModel mSatelliteOrbitModel; + private GpsSatelliteHealth mSatelliteHealth; + private SatelliteEphemerisTime mSatelliteEphemerisTime; + + /** Sets the PRN of the satellite. */ + @NonNull + public Builder setPrn(@IntRange(from = 1, to = 32) int prn) { + mPrn = prn; + return this; + } + + /** Sets the L2 parameters of the satellite. */ + @NonNull + public Builder setGpsL2Params(@NonNull GpsL2Params gpsL2Params) { + mGpsL2Params = gpsL2Params; + return this; + } + + /** Sets the clock model of the satellite. */ + @NonNull + public Builder setSatelliteClockModel(@NonNull GpsSatelliteClockModel satelliteClockModel) { + mSatelliteClockModel = satelliteClockModel; + return this; + } + + /** Sets the orbit model of the satellite. */ + @NonNull + public Builder setSatelliteOrbitModel(@NonNull KeplerianOrbitModel satelliteOrbitModel) { + mSatelliteOrbitModel = satelliteOrbitModel; + return this; + } + + /** Sets the satellite health. */ + @NonNull + public Builder setSatelliteHealth(@NonNull GpsSatelliteHealth satelliteHealth) { + mSatelliteHealth = satelliteHealth; + return this; + } + + /** Sets the ephemeris time. */ + @NonNull + public Builder setSatelliteEphemerisTime( + @NonNull SatelliteEphemerisTime satelliteEphemerisTime) { + mSatelliteEphemerisTime = satelliteEphemerisTime; + return this; + } + + /** Builds a {@link GpsSatelliteEphemeris} instance as specified by this builder. */ + @NonNull + public GpsSatelliteEphemeris build() { + return new GpsSatelliteEphemeris(this); + } + } + + /** + * A class contains information about GPS health. The information is tied to Legacy Navigation + * (LNAV) data, not Civil Navigation (CNAV) data. + */ + public static final class GpsSatelliteHealth implements Parcelable { + /** + * Represents "SV health" in the "BROADCAST ORBIT - 6" record of RINEX 3.05. Table A6, + * pp.68. + */ + private final int mSvHealth; + + /** + * Represents "SV accuracy" in meters in the "BROADCAST ORBIT - 6" record of RINEX 3.05. + * Table A6, pp.68. + */ + private final double mSvAccur; + + /** + * Represents the "Fit Interval" in hours in the "BROADCAST ORBIT - 7" record of RINEX 3.05. + * Table A6, pp.69. + */ + private final double mFitInt; + + /** Returns the SV health. */ + @IntRange(from = 0, to = 63) + public int getSvHealth() { + return mSvHealth; + } + + /** Returns the SV accuracy in meters. */ + @FloatRange(from = 0.0f, to = 8192.0f) + public double getSvAccur() { + return mSvAccur; + } + + /** Returns the fit interval in hours. */ + @FloatRange(from = 0.0f) + public double getFitInt() { + return mFitInt; + } + + private GpsSatelliteHealth(Builder builder) { + // Allow SV health beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSvHealth >= 0); + Preconditions.checkArgumentInRange(builder.mSvAccur, 0.0f, 8192.0f, "SvAccur"); + Preconditions.checkArgument(builder.mFitInt >= 0.0f); + mSvHealth = builder.mSvHealth; + mSvAccur = builder.mSvAccur; + mFitInt = builder.mFitInt; + } + + public static final @NonNull Creator<GpsSatelliteHealth> CREATOR = + new Creator<GpsSatelliteHealth>() { + @Override + @NonNull + public GpsSatelliteHealth createFromParcel(Parcel in) { + final GpsSatelliteHealth.Builder gpsSatelliteHealth = + new Builder() + .setSvHealth(in.readInt()) + .setSvAccur(in.readDouble()) + .setFitInt(in.readDouble()); + return gpsSatelliteHealth.build(); + } + + @Override + public GpsSatelliteHealth[] newArray(int size) { + return new GpsSatelliteHealth[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mSvHealth); + parcel.writeDouble(mSvAccur); + parcel.writeDouble(mFitInt); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GpsSatelliteHealth["); + builder.append("svHealth = ").append(mSvHealth); + builder.append(", svAccur = ").append(mSvAccur); + builder.append(", fitInt = ").append(mFitInt); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GpsSatelliteHealth}. */ + public static final class Builder { + private int mSvHealth; + private double mSvAccur; + private double mFitInt; + + /** Sets the SV health. */ + @NonNull + public Builder setSvHealth(@IntRange(from = 0, to = 63) int svHealth) { + mSvHealth = svHealth; + return this; + } + + /** Sets the SV accuracy in meters. */ + @NonNull + public Builder setSvAccur(@FloatRange(from = 0.0f, to = 8192.0f) double svAccur) { + mSvAccur = svAccur; + return this; + } + + /** Sets the fit interval in hours. */ + @NonNull + public Builder setFitInt(@FloatRange(from = 0.0f) double fitInt) { + mFitInt = fitInt; + return this; + } + + /** Builds a {@link GpsSatelliteHealth} instance as specified by this builder. */ + @NonNull + public GpsSatelliteHealth build() { + return new GpsSatelliteHealth(this); + } + } + } + + /** A class contains L2 parameters specific to GPS satellites. */ + public static final class GpsL2Params implements Parcelable { + /** Code(s) on L2 Channel. */ + private final int mL2Code; + + /** Data Flag for L2 P-Code. */ + private final int mL2Flag; + + /** Returns the code(s) on L2 channel. */ + @IntRange(from = 0, to = 3) + public int getL2Code() { + return mL2Code; + } + + /** Returns the data flag for L2 P-code. */ + @IntRange(from = 0, to = 1) + public int getL2Flag() { + return mL2Flag; + } + + private GpsL2Params(Builder builder) { + Preconditions.checkArgumentInRange(builder.mL2Code, 0, 3, "L2 code"); + Preconditions.checkArgumentInRange(builder.mL2Flag, 0, 1, "L2 flag"); + mL2Code = builder.mL2Code; + mL2Flag = builder.mL2Flag; + } + + public static final @NonNull Creator<GpsL2Params> CREATOR = + new Creator<GpsL2Params>() { + @Override + @NonNull + public GpsL2Params createFromParcel(Parcel in) { + final GpsL2Params.Builder gpsL2Params = + new Builder().setL2Code(in.readInt()).setL2Flag(in.readInt()); + return gpsL2Params.build(); + } + + @Override + public GpsL2Params[] newArray(int size) { + return new GpsL2Params[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mL2Code); + parcel.writeInt(mL2Flag); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GpsL2Params["); + builder.append("l2Code = ").append(mL2Code); + builder.append(", l2Flag = ").append(mL2Flag); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GpsL2Params}. */ + public static final class Builder { + private int mL2Code = 0; + private int mL2Flag = 0; + + /** Sets the code(s) on L2 channel. */ + @NonNull + public Builder setL2Code(@IntRange(from = 0, to = 3) int l2Code) { + mL2Code = l2Code; + return this; + } + + /** Sets the data flag for L2 P-code. */ + @NonNull + public Builder setL2Flag(@IntRange(from = 0, to = 1) int l2Flag) { + mL2Flag = l2Flag; + return this; + } + + /** Builds a {@link GpsL2Params} instance as specified by this builder. */ + @NonNull + public GpsL2Params build() { + return new GpsL2Params(this); + } + } + } + + /** A class contains the set of parameters needed for GPS satellite clock correction. */ + public static final class GpsSatelliteClockModel implements Parcelable { + /** + * Time of the clock in seconds since GPS epoch. + * + * <p>Corresponds to the 'Epoch' field within the 'SV/EPOCH/SV CLK' record of GPS + * navigation message in RINEX 3.05 Table A6. + */ + private final long mTimeOfClockSeconds; + + /** SV clock bias in seconds. */ + private final double mAf0; + + /** SV clock drift in seconds per second. */ + private final double mAf1; + + /** Clock drift rate in seconds per second squared. */ + private final double mAf2; + + /** Group delay differential in seconds. */ + private final double mTgd; + + /** Issue of data, clock. */ + private final int mIodc; + + private GpsSatelliteClockModel(Builder builder) { + Preconditions.checkArgument(builder.mTimeOfClockSeconds >= 0); + Preconditions.checkArgumentInRange(builder.mAf0, -9.77e-3f, 9.77e-3f, "Af0"); + Preconditions.checkArgumentInRange(builder.mAf1, -3.73e-9f, 3.73e-9f, "Af1"); + Preconditions.checkArgumentInRange(builder.mAf2, -3.56e-15f, 3.56e-15f, "Af2"); + Preconditions.checkArgumentInRange(builder.mTgd, -5.97e-8f, 5.97e-8f, "Tgd"); + Preconditions.checkArgumentInRange(builder.mIodc, 0, 1023, "Iodc"); + mTimeOfClockSeconds = builder.mTimeOfClockSeconds; + mAf0 = builder.mAf0; + mAf1 = builder.mAf1; + mAf2 = builder.mAf2; + mTgd = builder.mTgd; + mIodc = builder.mIodc; + } + + /** Returns the time of the clock in seconds since GPS epoch. */ + @IntRange(from = 0) + public long getTimeOfClockSeconds() { + return mTimeOfClockSeconds; + } + + /** Returns the SV clock bias in seconds. */ + @FloatRange(from = -9.77e-3f, to = 9.77e-3f) + public double getAf0() { + return mAf0; + } + + /** Returns the SV clock drift in seconds per second. */ + @FloatRange(from = -3.73e-9f, to = 3.73e-9f) + public double getAf1() { + return mAf1; + } + + /** Returns the clock drift rate in seconds per second squared. */ + @FloatRange(from = -3.56e-15f, to = 3.56e-15f) + public double getAf2() { + return mAf2; + } + + /** Returns the group delay differential in seconds. */ + @FloatRange(from = -5.97e-8f, to = 5.97e-8f) + public double getTgd() { + return mTgd; + } + + /** Returns the issue of data, clock. */ + @IntRange(from = 0, to = 1023) + public int getIodc() { + return mIodc; + } + + public static final @NonNull Creator<GpsSatelliteClockModel> CREATOR = + new Creator<GpsSatelliteClockModel>() { + @Override + @NonNull + public GpsSatelliteClockModel createFromParcel(Parcel in) { + final GpsSatelliteClockModel.Builder gpsSatelliteClockModel = + new Builder() + .setTimeOfClockSeconds(in.readLong()) + .setAf0(in.readDouble()) + .setAf1(in.readDouble()) + .setAf2(in.readDouble()) + .setTgd(in.readDouble()) + .setIodc(in.readInt()); + return gpsSatelliteClockModel.build(); + } + + @Override + public GpsSatelliteClockModel[] newArray(int size) { + return new GpsSatelliteClockModel[size]; + } + }; + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeLong(mTimeOfClockSeconds); + parcel.writeDouble(mAf0); + parcel.writeDouble(mAf1); + parcel.writeDouble(mAf2); + parcel.writeDouble(mTgd); + parcel.writeInt(mIodc); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("GpsSatelliteClockModel["); + builder.append("timeOfClockSeconds = ").append(mTimeOfClockSeconds); + builder.append(", af0 = ").append(mAf0); + builder.append(", af1 = ").append(mAf1); + builder.append(", af2 = ").append(mAf2); + builder.append(", tgd = ").append(mTgd); + builder.append(", iodc = ").append(mIodc); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link GpsSatelliteClockModel}. */ + public static final class Builder { + private long mTimeOfClockSeconds; + private double mAf0; + private double mAf1; + private double mAf2; + private double mTgd; + private int mIodc; + + /** Sets the time of the clock in seconds since GPS epoch. */ + @NonNull + public Builder setTimeOfClockSeconds(@IntRange(from = 0) long timeOfClockSeconds) { + mTimeOfClockSeconds = timeOfClockSeconds; + return this; + } + + /** Sets the SV clock bias in seconds. */ + @NonNull + public Builder setAf0(@FloatRange(from = -9.77e-3f, to = 9.77e-3f) double af0) { + mAf0 = af0; + return this; + } + + /** Sets the SV clock drift in seconds per second. */ + @NonNull + public Builder setAf1(@FloatRange(from = -3.73e-9f, to = 3.73e-9f) double af1) { + mAf1 = af1; + return this; + } + + /** Sets the clock drift rate in seconds per second squared. */ + @NonNull + public Builder setAf2(@FloatRange(from = -3.56e-15f, to = 3.56e-15f) double af2) { + mAf2 = af2; + return this; + } + + /** Sets the group delay differential in seconds. */ + @NonNull + public Builder setTgd(@FloatRange(from = -5.97e-8f, to = 5.97e-8f) double tgd) { + mTgd = tgd; + return this; + } + + /** Sets the issue of data, clock. */ + @NonNull + public Builder setIodc(@IntRange(from = 0, to = 1023) int iodc) { + mIodc = iodc; + return this; + } + + /** Builds a {@link GpsSatelliteClockModel} instance as specified by this builder. */ + @NonNull + public GpsSatelliteClockModel build() { + return new GpsSatelliteClockModel(this); + } + } + } +} diff --git a/location/java/android/location/IonosphericCorrection.java b/location/java/android/location/IonosphericCorrection.java new file mode 100644 index 000000000000..aafcf8301add --- /dev/null +++ b/location/java/android/location/IonosphericCorrection.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains ionospheric correction. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class IonosphericCorrection implements Parcelable { + + /** Carrier frequency in Hz to differentiate signals from the same satellite. e.g. GPS L1/L5 */ + private final long mCarrierFrequencyHz; + + /** Ionospheric correction. */ + @NonNull private final GnssCorrectionComponent mIonosphericCorrection; + + /** + * Creates a new {@link IonosphericCorrection} instance. + * + * @param carrierFrequencyHz Carrier frequency in Hz to differentiate signals from the + * samesatellite. e.g. GPS L1/L5 + * @param ionosphericCorrection Ionospheric correction. + */ + public IonosphericCorrection( + @IntRange(from = 0) long carrierFrequencyHz, + @NonNull GnssCorrectionComponent ionosphericCorrection) { + Preconditions.checkArgument(carrierFrequencyHz > 0); + Preconditions.checkNotNull(ionosphericCorrection, "IonosphericCorrection cannot be null"); + mCarrierFrequencyHz = carrierFrequencyHz; + mIonosphericCorrection = ionosphericCorrection; + } + + /** + * Returns the carrier frequency in Hz to differentiate signals from the same satellite. e.g. + * GPS L1/L5 + */ + @IntRange(from = 0) + public long getCarrierFrequencyHz() { + return mCarrierFrequencyHz; + } + + /** Returns the Ionospheric correction. */ + @NonNull + public GnssCorrectionComponent getIonosphericCorrection() { + return mIonosphericCorrection; + } + + public static final @NonNull Creator<IonosphericCorrection> CREATOR = + new Creator<IonosphericCorrection>() { + @Override + @NonNull + public IonosphericCorrection createFromParcel(Parcel in) { + long carrierFrequencyHz = in.readLong(); + GnssCorrectionComponent ionosphericCorrection = + in.readTypedObject(GnssCorrectionComponent.CREATOR); + return new IonosphericCorrection(carrierFrequencyHz, ionosphericCorrection); + } + + @Override + public IonosphericCorrection[] newArray(int size) { + return new IonosphericCorrection[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mCarrierFrequencyHz); + dest.writeTypedObject(mIonosphericCorrection, flags); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("IonosphericCorrection["); + builder.append("carrierFrequencyHz = ").append(mCarrierFrequencyHz); + builder.append(", ionosphericCorrection = ").append(mIonosphericCorrection); + builder.append("]"); + return builder.toString(); + } +} diff --git a/location/java/android/location/KeplerianOrbitModel.java b/location/java/android/location/KeplerianOrbitModel.java new file mode 100644 index 000000000000..a118274dc9a3 --- /dev/null +++ b/location/java/android/location/KeplerianOrbitModel.java @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * Contains Keplerian orbit model parameters for GPS/Galileo/QZSS/Beidou. + * <p>For GPS, this is defined in IS-GPS-200 Table 20-II. + * <p>For Galileo, this is defined in Galileo-OS-SIS-ICD-v2.1 section 5.1.1. + * <p>For QZSS, this is defined in IS-QZSS-PNT section 4.1.2. + * <p>For Baidou, this is defined in BDS-SIS-ICD-B1I-3.0 section 5.2.4.12. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class KeplerianOrbitModel implements Parcelable { + /** Square root of the semi-major axis in square root of meters. */ + private final double mRootA; + + /** Eccentricity. */ + private final double mEccentricity; + + /** Inclination angle at reference time in radians. */ + private final double mI0; + + /** Rate of change of inclination angle in radians per second. */ + private final double mIDot; + + /** Argument of perigee in radians. */ + private final double mOmega; + + /** Longitude of ascending node of orbit plane at beginning of week in radians. */ + private final double mOmega0; + + /** Rate of right ascension in radians per second. */ + private final double mOmegaDot; + + /** Mean anomaly at reference time in radians. */ + private final double mM0; + + /** Mean motion difference from computed value in radians per second. */ + private final double mDeltaN; + + /** Second-order harmonic perturbations. */ + SecondOrderHarmonicPerturbation mSecondOrderHarmonicPerturbation; + + private KeplerianOrbitModel(Builder builder) { + Preconditions.checkArgumentInRange(builder.mRootA, 0.0f, 8192.0f, "RootA"); + Preconditions.checkArgumentInRange(builder.mEccentricity, 0.0f, 0.5f, "Eccentricity"); + Preconditions.checkArgumentInRange(builder.mI0, -3.15f, 3.15f, "I0"); + Preconditions.checkArgumentInRange(builder.mIDot, -2.94e-9f, 2.94e-9f, "IDot"); + Preconditions.checkArgumentInRange(builder.mOmega, -3.15f, 3.15f, "Omega"); + Preconditions.checkArgumentInRange(builder.mOmega0, -3.15f, 3.15f, "Omega0"); + Preconditions.checkArgumentInRange(builder.mOmegaDot, -3.1e-6f, 3.1e-6f, "OmegaDot"); + Preconditions.checkArgumentInRange(builder.mM0, -3.15f, 3.15f, "M0"); + Preconditions.checkArgumentInRange(builder.mDeltaN, -1.18e-8f, 1.18e-8f, "DeltaN"); + mRootA = builder.mRootA; + mEccentricity = builder.mEccentricity; + mI0 = builder.mI0; + mIDot = builder.mIDot; + mOmega = builder.mOmega; + mOmega0 = builder.mOmega0; + mOmegaDot = builder.mOmegaDot; + mM0 = builder.mM0; + mDeltaN = builder.mDeltaN; + mSecondOrderHarmonicPerturbation = builder.mSecondOrderHarmonicPerturbation; + } + + /** Get the square root of the semi-major axis in square root of meters. */ + @FloatRange(from = 0.0f, to = 8192.0f) + public double getRootA() { + return mRootA; + } + + /** Get the eccentricity. */ + @FloatRange(from = 0.0f, to = 0.5f) + public double getEccentricity() { + return mEccentricity; + } + + /** Get the inclination angle at reference time in radians. */ + @FloatRange(from = -3.15f, to = 3.15f) + public double getI0() { + return mI0; + } + + /** Get the rate of change of inclination angle in radians per second. */ + @FloatRange(from = -2.94e-9f, to = 2.94e-9f) + public double getIDot() { + return mIDot; + } + + /** Get the argument of perigee in radians. */ + @FloatRange(from = -3.15f, to = 3.15f) + public double getOmega() { + return mOmega; + } + + /** Get the longitude of ascending node of orbit plane at beginning of week in radians. */ + @FloatRange(from = -3.15f, to = 3.15f) + public double getOmega0() { + return mOmega0; + } + + /** Get the rate of right ascension in radians per second. */ + @FloatRange(from = -3.1e-6f, to = 3.1e-6f) + public double getOmegaDot() { + return mOmegaDot; + } + + /** Get the mean anomaly at reference time in radians. */ + @FloatRange(from = -3.15f, to = 3.15f) + public double getM0() { + return mM0; + } + + /** Get the mean motion difference from computed value in radians per second. */ + @FloatRange(from = -1.18e-8f, to = 1.18e-8f) + public double getDeltaN() { + return mDeltaN; + } + + /** Get the second-order harmonic perturbations. */ + @NonNull + public SecondOrderHarmonicPerturbation getSecondOrderHarmonicPerturbation() { + return mSecondOrderHarmonicPerturbation; + } + + public static final @NonNull Creator<KeplerianOrbitModel> CREATOR = + new Creator<KeplerianOrbitModel>() { + @Override + @NonNull + public KeplerianOrbitModel createFromParcel(Parcel in) { + final KeplerianOrbitModel.Builder keplerianOrbitModel = + new Builder() + .setRootA(in.readDouble()) + .setEccentricity(in.readDouble()) + .setI0(in.readDouble()) + .setIDot(in.readDouble()) + .setOmega(in.readDouble()) + .setOmega0(in.readDouble()) + .setOmegaDot(in.readDouble()) + .setM0(in.readDouble()) + .setDeltaN(in.readDouble()) + .setSecondOrderHarmonicPerturbation( + in.readTypedObject( + SecondOrderHarmonicPerturbation.CREATOR)); + return keplerianOrbitModel.build(); + } + + @Override + public KeplerianOrbitModel[] newArray(int size) { + return new KeplerianOrbitModel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeDouble(mRootA); + parcel.writeDouble(mEccentricity); + parcel.writeDouble(mI0); + parcel.writeDouble(mIDot); + parcel.writeDouble(mOmega); + parcel.writeDouble(mOmega0); + parcel.writeDouble(mOmegaDot); + parcel.writeDouble(mM0); + parcel.writeDouble(mDeltaN); + parcel.writeTypedObject(mSecondOrderHarmonicPerturbation, flags); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("KeplerianOrbitModel["); + builder.append("rootA = ").append(mRootA); + builder.append(", eccentricity = ").append(mEccentricity); + builder.append(", i0 = ").append(mI0); + builder.append(", iDot = ").append(mIDot); + builder.append(", omega = ").append(mOmega); + builder.append(", omega0 = ").append(mOmega0); + builder.append(", omegaDot = ").append(mOmegaDot); + builder.append(", m0 = ").append(mM0); + builder.append(", deltaN = ").append(mDeltaN); + builder.append(", secondOrderHarmonicPerturbation = ") + .append(mSecondOrderHarmonicPerturbation); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link KeplerianOrbitModel} */ + public static final class Builder { + private double mRootA; + private double mEccentricity; + private double mI0; + private double mIDot; + private double mOmega; + private double mOmega0; + private double mOmegaDot; + private double mM0; + private double mDeltaN; + private SecondOrderHarmonicPerturbation mSecondOrderHarmonicPerturbation; + + /** Sets the square root of the semi-major axis in square root of meters. */ + @NonNull + public Builder setRootA(@FloatRange(from = 0.0f, to = 8192.0f) double rootA) { + mRootA = rootA; + return this; + } + + /** Sets the eccentricity. */ + @NonNull + public Builder setEccentricity(@FloatRange(from = 0.0f, to = 0.5f) double eccentricity) { + mEccentricity = eccentricity; + return this; + } + + /** Sets the inclination angle at reference time in radians. */ + @NonNull + public Builder setI0(@FloatRange(from = -3.15f, to = 3.15f) double i0) { + mI0 = i0; + return this; + } + + /** Sets the rate of change of inclination angle in radians per second. */ + @NonNull + public Builder setIDot(@FloatRange(from = -2.94e-9f, to = 2.94e-9f) double iDot) { + mIDot = iDot; + return this; + } + + /** Sets the argument of perigee in radians. */ + @NonNull + public Builder setOmega(@FloatRange(from = -3.15f, to = 3.15f) double omega) { + mOmega = omega; + return this; + } + + /** + * Sets the longitude of ascending node of orbit plane at beginning of week in radians. + */ + @NonNull + public Builder setOmega0(@FloatRange(from = -3.15f, to = 3.15f) double omega0) { + mOmega0 = omega0; + return this; + } + + /** Sets the rate of right ascension in radians per second. */ + @NonNull + public Builder setOmegaDot(@FloatRange(from = -3.1e-6f, to = 3.1e-6f) double omegaDot) { + mOmegaDot = omegaDot; + return this; + } + + /** Sets the mean anomaly at reference time in radians. */ + @NonNull + public Builder setM0(@FloatRange(from = -3.15f, to = 3.15f) double m0) { + mM0 = m0; + return this; + } + + /** Sets the mean motion difference from computed value in radians per second. */ + @NonNull + public Builder setDeltaN(@FloatRange(from = -1.18e-8f, to = 1.18e-8f) double deltaN) { + mDeltaN = deltaN; + return this; + } + + /** Sets the second-order harmonic perturbations. */ + @NonNull + public Builder setSecondOrderHarmonicPerturbation( + @NonNull SecondOrderHarmonicPerturbation secondOrderHarmonicPerturbation) { + mSecondOrderHarmonicPerturbation = secondOrderHarmonicPerturbation; + return this; + } + + /** Builds a {@link KeplerianOrbitModel} instance as specified by this builder. */ + @NonNull + public KeplerianOrbitModel build() { + return new KeplerianOrbitModel(this); + } + } + + /** A class contains second-order harmonic perturbations. */ + public static final class SecondOrderHarmonicPerturbation implements Parcelable { + /** Amplitude of cosine harmonic correction term to angle of inclination in radians. */ + private final double mCic; + + /** Amplitude of sine harmonic correction term to angle of inclination in radians. */ + private final double mCis; + + /** Amplitude of cosine harmonic correction term to the orbit in meters. */ + private final double mCrc; + + /** Amplitude of sine harmonic correction term to the orbit in meters. */ + private final double mCrs; + + /** Amplitude of cosine harmonic correction term to the argument of latitude in radians. */ + private final double mCuc; + + /** Amplitude of sine harmonic correction term to the argument of latitude in radians. */ + private final double mCus; + + private SecondOrderHarmonicPerturbation(Builder builder) { + Preconditions.checkArgumentInRange(builder.mCic, -6.11e-5f, 6.11e-5f, "Cic"); + Preconditions.checkArgumentInRange(builder.mCis, -6.11e-5f, 6.11e-5f, "Cis"); + Preconditions.checkArgumentInRange(builder.mCrc, -2048.0f, 2048.0f, "Crc"); + Preconditions.checkArgumentInRange(builder.mCrs, -2048.0f, 2048.0f, "Crs"); + Preconditions.checkArgumentInRange(builder.mCuc, -6.11e-5f, 6.11e-5f, "Cuc"); + Preconditions.checkArgumentInRange(builder.mCus, -6.11e-5f, 6.11e-5f, "Cus"); + mCic = builder.mCic; + mCrc = builder.mCrc; + mCis = builder.mCis; + mCrs = builder.mCrs; + mCuc = builder.mCuc; + mCus = builder.mCus; + } + + /** + * Get the amplitude of cosine harmonic correction term to angle of inclination in radians. + */ + @FloatRange(from = -6.11e-5f, to = 6.11e-5f) + public double getCic() { + return mCic; + } + + /** + * Get the amplitude of sine harmonic correction term to angle of inclination in radians. + */ + @FloatRange(from = -6.11e-5f, to = 6.11e-5f) + public double getCis() { + return mCis; + } + + /** Get the amplitude of cosine harmonic correction term to the orbit in meters. */ + @FloatRange(from = -2048.0f, to = 2048.0f) + public double getCrc() { + return mCrc; + } + + /** Get the amplitude of sine harmonic correction term to the orbit in meters. */ + @FloatRange(from = -2048.0f, to = 2048.0f) + public double getCrs() { + return mCrs; + } + + /** + * Get the amplitude of cosine harmonic correction term to the argument of latitude in + * radians. + */ + @FloatRange(from = -6.11e-5f, to = 6.11e-5f) + public double getCuc() { + return mCuc; + } + + /** + * Get the amplitude of sine harmonic correction term to the argument of latitude in + * radians. + */ + @FloatRange(from = -6.11e-5f, to = 6.11e-5f) + public double getCus() { + return mCus; + } + + public static final @NonNull Creator<SecondOrderHarmonicPerturbation> CREATOR = + new Creator<SecondOrderHarmonicPerturbation>() { + @Override + @NonNull + public SecondOrderHarmonicPerturbation createFromParcel(Parcel in) { + final SecondOrderHarmonicPerturbation.Builder + secondOrderHarmonicPerturbation = + new Builder() + .setCic(in.readDouble()) + .setCis(in.readDouble()) + .setCrc(in.readDouble()) + .setCrs(in.readDouble()) + .setCuc(in.readDouble()) + .setCus(in.readDouble()); + return secondOrderHarmonicPerturbation.build(); + } + + @Override + public SecondOrderHarmonicPerturbation[] newArray(int size) { + return new SecondOrderHarmonicPerturbation[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeDouble(mCic); + parcel.writeDouble(mCis); + parcel.writeDouble(mCrc); + parcel.writeDouble(mCrs); + parcel.writeDouble(mCuc); + parcel.writeDouble(mCus); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("SecondOrderHarmonicPerturbation["); + builder.append("cic = ").append(mCic); + builder.append(", cis = ").append(mCis); + builder.append(", crc = ").append(mCrc); + builder.append(", crs = ").append(mCrs); + builder.append(", cuc = ").append(mCuc); + builder.append(", cus = ").append(mCus); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link SecondOrderHarmonicPerturbation} */ + public static final class Builder { + private double mCic; + private double mCis; + private double mCrc; + private double mCrs; + private double mCuc; + private double mCus; + + /** + * Sets the amplitude of cosine harmonic correction term to angle of inclination in + * radians. + */ + @NonNull + public Builder setCic(@FloatRange(from = -6.11e-5f, to = 6.11e-5f) double cic) { + mCic = cic; + return this; + } + + /** + * Sets the amplitude of sine harmonic correction term to angle of inclination in + * radians. + */ + @NonNull + public Builder setCis(@FloatRange(from = -6.11e-5f, to = 6.11e-5f) double cis) { + mCis = cis; + return this; + } + + /** Sets the amplitude of cosine harmonic correction term to the orbit in meters. */ + @NonNull + public Builder setCrc(@FloatRange(from = -2048.0f, to = 2048.0f) double crc) { + mCrc = crc; + return this; + } + + /** Sets the amplitude of sine harmonic correction term to the orbit in meters. */ + @NonNull + public Builder setCrs(@FloatRange(from = -2048.0f, to = 2048.0f) double crs) { + mCrs = crs; + return this; + } + + /** + * Sets the amplitude of cosine harmonic correction term to the argument of latitude in + * radians. + */ + @NonNull + public Builder setCuc(@FloatRange(from = -6.11e-5f, to = 6.11e-5f) double cuc) { + mCuc = cuc; + return this; + } + + /** + * Sets the amplitude of sine harmonic correction term to the argument of latitude in + * radians. + */ + @NonNull + public Builder setCus(@FloatRange(from = -6.11e-5f, to = 6.11e-5f) double cus) { + mCus = cus; + return this; + } + + /** + * Builds a {@link SecondOrderHarmonicPerturbation} instance as specified by this + * builder. + */ + @NonNull + public SecondOrderHarmonicPerturbation build() { + return new SecondOrderHarmonicPerturbation(this); + } + } + } +} diff --git a/location/java/android/location/KlobucharIonosphericModel.java b/location/java/android/location/KlobucharIonosphericModel.java new file mode 100644 index 000000000000..d239c876f702 --- /dev/null +++ b/location/java/android/location/KlobucharIonosphericModel.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains Klobuchar ionospheric model coefficients used by GPS, BDS, QZSS. + * + * <p>This is defined in IS-GPS-200 section 20.3.3.5.1.7. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class KlobucharIonosphericModel implements Parcelable { + /** Alpha0 coefficientin seconds. */ + double mAlpha0; + /** Alpha1 coefficient in seconds per semi-circle. */ + double mAlpha1; + /** Alpha2 coefficient in seconds per semi-circle squared. */ + double mAlpha2; + /** Alpha3 coefficient in seconds per semi-circle cubed. */ + double mAlpha3; + /** Beta0 coefficient in seconds. */ + double mBeta0; + /** Beta1 coefficient in seconds per semi-circle. */ + double mBeta1; + /** Beta2 coefficient in seconds per semi-circle squared. */ + double mBeta2; + /** Beta3 coefficient in seconds per semi-circle cubed. */ + double mBeta3; + + private KlobucharIonosphericModel(Builder builder) { + Preconditions.checkArgumentInRange(builder.mAlpha0, -1.193e-7f, 1.193e-7f, "Alpha0"); + Preconditions.checkArgumentInRange(builder.mAlpha1, -9.54e-7f, 9.54e-7f, "Alpha1"); + Preconditions.checkArgumentInRange(builder.mAlpha2, -7.63e-6f, 7.63e-6f, "Alpha2"); + Preconditions.checkArgumentInRange(builder.mAlpha3, -7.63e-6f, 7.63e-6f, "Alpha3"); + Preconditions.checkArgumentInRange(builder.mBeta0, -262144.0f, 262144.0f, "Beta0"); + Preconditions.checkArgumentInRange(builder.mBeta1, -2097152.0f, 2097152.0f, "Beta1"); + Preconditions.checkArgumentInRange(builder.mBeta2, -8388608.0f, 8388608.0f, "Beta2"); + Preconditions.checkArgumentInRange(builder.mBeta3, -8388608.0f, 8388608.0f, "Beta3"); + mAlpha0 = builder.mAlpha0; + mAlpha1 = builder.mAlpha1; + mAlpha2 = builder.mAlpha2; + mAlpha3 = builder.mAlpha3; + mBeta0 = builder.mBeta0; + mBeta1 = builder.mBeta1; + mBeta2 = builder.mBeta2; + mBeta3 = builder.mBeta3; + } + + /** Returns the alpha0 coefficient in seconds. */ + @FloatRange(from = -1.193e-7f, to = 1.193e-7f) + public double getAlpha0() { + return mAlpha0; + } + + /** Returns the alpha1 coefficient in seconds per semi-circle. */ + @FloatRange(from = -9.54e-7f, to = 9.54e-7f) + public double getAlpha1() { + return mAlpha1; + } + + /** Returns the alpha2 coefficient in seconds per semi-circle squared. */ + @FloatRange(from = -7.63e-6f, to = 7.63e-6f) + public double getAlpha2() { + return mAlpha2; + } + + /** Returns the alpha3 coefficient in seconds per semi-circle cubed. */ + @FloatRange(from = -7.63e-6f, to = 7.63e-6f) + public double getAlpha3() { + return mAlpha3; + } + + /** Returns the beta0 coefficient in seconds. */ + @FloatRange(from = -262144.0f, to = 262144.0f) + public double getBeta0() { + return mBeta0; + } + + /** Returns the beta1 coefficient in seconds per semi-circle. */ + @FloatRange(from = -2097152.0f, to = 2097152.0f) + public double getBeta1() { + return mBeta1; + } + + /** Returns the beta2 coefficient in seconds per semi-circle squared. */ + @FloatRange(from = -8388608.0f, to = 8388608.0f) + public double getBeta2() { + return mBeta2; + } + + /** Returns the beta3 coefficient in seconds per semi-circle cubed. */ + @FloatRange(from = -8388608.0f, to = 8388608.0f) + public double getBeta3() { + return mBeta3; + } + + public static final @NonNull Creator<KlobucharIonosphericModel> CREATOR = + new Creator<KlobucharIonosphericModel>() { + @Override + @NonNull + public KlobucharIonosphericModel createFromParcel(Parcel in) { + return new KlobucharIonosphericModel.Builder() + .setAlpha0(in.readDouble()) + .setAlpha1(in.readDouble()) + .setAlpha2(in.readDouble()) + .setAlpha3(in.readDouble()) + .setBeta0(in.readDouble()) + .setBeta1(in.readDouble()) + .setBeta2(in.readDouble()) + .setBeta3(in.readDouble()) + .build(); + } + @Override + public KlobucharIonosphericModel[] newArray(int size) { + return new KlobucharIonosphericModel[size]; + } + }; + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeDouble(mAlpha0); + parcel.writeDouble(mAlpha1); + parcel.writeDouble(mAlpha2); + parcel.writeDouble(mAlpha3); + parcel.writeDouble(mBeta0); + parcel.writeDouble(mBeta1); + parcel.writeDouble(mBeta2); + parcel.writeDouble(mBeta3); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("KlobucharIonosphericModel["); + builder.append("alpha0 = ").append(mAlpha0); + builder.append(", alpha1 = ").append(mAlpha1); + builder.append(", alpha2 = ").append(mAlpha2); + builder.append(", alpha3 = ").append(mAlpha3); + builder.append(", beta0 = ").append(mBeta0); + builder.append(", beta1 = ").append(mBeta1); + builder.append(", beta2 = ").append(mBeta2); + builder.append(", beta3 = ").append(mBeta3); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link KlobucharIonosphericModel} */ + public static final class Builder { + private double mAlpha0; + private double mAlpha1; + private double mAlpha2; + private double mAlpha3; + private double mBeta0; + private double mBeta1; + private double mBeta2; + private double mBeta3; + + /** Sets the alpha0 coefficient in seconds. */ + @NonNull + public Builder setAlpha0(@FloatRange(from = -1.193e-7f, to = 1.193e-7f) double alpha0) { + mAlpha0 = alpha0; + return this; + } + + /** Sets the alpha1 coefficient in seconds per semi-circle. */ + @NonNull + public Builder setAlpha1(@FloatRange(from = -9.54e-7f, to = 9.54e-7f) double alpha1) { + mAlpha1 = alpha1; + return this; + } + + /** Sets the alpha2 coefficient in seconds per semi-circle squared. */ + @NonNull + public Builder setAlpha2(@FloatRange(from = -7.63e-6f, to = 7.63e-6f) double alpha2) { + mAlpha2 = alpha2; + return this; + } + + /** Sets the alpha3 coefficient in seconds per semi-circle cubed. */ + @NonNull + public Builder setAlpha3(@FloatRange(from = -7.63e-6f, to = 7.63e-6f) double alpha3) { + mAlpha3 = alpha3; + return this; + } + + /** Sets the beta0 coefficient in seconds. */ + @NonNull + public Builder setBeta0(@FloatRange(from = -262144.0f, to = 262144.0f) double beta0) { + mBeta0 = beta0; + return this; + } + + /** Sets the beta1 coefficient in seconds per semi-circle. */ + @NonNull + public Builder setBeta1(@FloatRange(from = -2097152.0f, to = 2097152.0f) double beta1) { + mBeta1 = beta1; + return this; + } + + /** Sets the beta2 coefficient in seconds per semi-circle squared. */ + @NonNull + public Builder setBeta2(@FloatRange(from = -8388608.0f, to = 8388608.0f) double beta2) { + mBeta2 = beta2; + return this; + } + + /** Sets the beta3 coefficient in seconds per semi-circle cubed. */ + @NonNull + public Builder setBeta3(@FloatRange(from = -8388608.0f, to = 8388608.0f) double beta3) { + mBeta3 = beta3; + return this; + } + + /** Builds a {@link KlobucharIonosphericModel} instance as specified by this builder. */ + @NonNull + public KlobucharIonosphericModel build() { + return new KlobucharIonosphericModel(this); + } + } +} diff --git a/location/java/android/location/LeapSecondsModel.java b/location/java/android/location/LeapSecondsModel.java new file mode 100644 index 000000000000..bc132addb06a --- /dev/null +++ b/location/java/android/location/LeapSecondsModel.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * Contains the leap seconds set of parameters needed for GNSS time. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class LeapSecondsModel implements Parcelable { + /** Time difference due to leap seconds before the event in seconds. (UTC) */ + private final int mLeapSeconds; + + /** Time difference due to leap seconds after the event in seconds. (UTC) */ + private final int mLeapSecondsFuture; + + /** GNSS week number in which the leap second event will occur. (UTC) */ + private final int mWeekNumberLeapSecondsFuture; + + /** Day number when the next leap second will occur. */ + private final int mDayNumberLeapSecondsFuture; + + private LeapSecondsModel(Builder builder) { + Preconditions.checkArgument(builder.mLeapSeconds >= 0); + Preconditions.checkArgument(builder.mLeapSecondsFuture >= 0); + Preconditions.checkArgument(builder.mWeekNumberLeapSecondsFuture >= 0); + Preconditions.checkArgument(builder.mDayNumberLeapSecondsFuture >= 0); + mLeapSeconds = builder.mLeapSeconds; + mLeapSecondsFuture = builder.mLeapSecondsFuture; + mWeekNumberLeapSecondsFuture = builder.mWeekNumberLeapSecondsFuture; + mDayNumberLeapSecondsFuture = builder.mDayNumberLeapSecondsFuture; + } + + /** Returns the time difference due to leap seconds before the event in seconds. (UTC) */ + @IntRange(from = 0) + public int getLeapSeconds() { + return mLeapSeconds; + } + + /** Returns the time difference due to leap seconds after the event in seconds. (UTC) */ + @IntRange(from = 0) + public int getLeapSecondsFuture() { + return mLeapSecondsFuture; + } + + /** Returns the GNSS week number in which the leap second event will occur. (UTC) */ + @IntRange(from = 0) + public int getWeekNumberLeapSecondsFuture() { + return mWeekNumberLeapSecondsFuture; + } + + /** Returns the day number when the next leap second will occur. */ + @IntRange(from = 0) + public int getDayNumberLeapSecondsFuture() { + return mDayNumberLeapSecondsFuture; + } + + public static final @NonNull Creator<LeapSecondsModel> CREATOR = + new Creator<LeapSecondsModel>() { + @Override + @NonNull + public LeapSecondsModel createFromParcel(Parcel in) { + final LeapSecondsModel.Builder leapSecondsModel = new Builder(); + leapSecondsModel.setLeapSeconds(in.readInt()); + leapSecondsModel.setLeapSecondsFuture(in.readInt()); + leapSecondsModel.setWeekNumberLeapSecondsFuture(in.readInt()); + leapSecondsModel.setDayNumberLeapSecondsFuture(in.readInt()); + return leapSecondsModel.build(); + } + + @Override + public LeapSecondsModel[] newArray(int size) { + return new LeapSecondsModel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mLeapSeconds); + parcel.writeInt(mLeapSecondsFuture); + parcel.writeInt(mWeekNumberLeapSecondsFuture); + parcel.writeInt(mDayNumberLeapSecondsFuture); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("LeapSecondsModel["); + builder.append("leapSeconds = ").append(mLeapSeconds); + builder.append(", leapSecondsFuture = ").append(mLeapSecondsFuture); + builder.append(", weekNumberLeapSecondsFuture = ").append(mWeekNumberLeapSecondsFuture); + builder.append(", dayNumberLeapSecondsFuture = ").append(mDayNumberLeapSecondsFuture); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link LeapSecondsModel} */ + public static final class Builder { + private int mLeapSeconds; + private int mLeapSecondsFuture; + private int mWeekNumberLeapSecondsFuture; + private int mDayNumberLeapSecondsFuture; + + /** Sets the time difference due to leap seconds before the event in seconds. (UTC) */ + @NonNull + public Builder setLeapSeconds(@IntRange(from = 0) int leapSeconds) { + mLeapSeconds = leapSeconds; + return this; + } + + /** Sets the time difference due to leap seconds after the event in seconds. (UTC) */ + @NonNull + public Builder setLeapSecondsFuture(@IntRange(from = 0) int leapSecondsFuture) { + mLeapSecondsFuture = leapSecondsFuture; + return this; + } + + /** Sets the GNSS week number in which the leap second event will occur. (UTC) */ + @NonNull + public Builder setWeekNumberLeapSecondsFuture( + @IntRange(from = 0) int weekNumberLeapSecondsFuture) { + mWeekNumberLeapSecondsFuture = weekNumberLeapSecondsFuture; + return this; + } + + /** Sets the day number when the next leap second will occur. */ + @NonNull + public Builder setDayNumberLeapSecondsFuture( + @IntRange(from = 0) int dayNumberLeapSecondsFuture) { + mDayNumberLeapSecondsFuture = dayNumberLeapSecondsFuture; + return this; + } + + /** Builds a {@link LeapSecondsModel} instance as specified by this builder. */ + @NonNull + public LeapSecondsModel build() { + return new LeapSecondsModel(this); + } + } +} diff --git a/location/java/android/location/QzssAssistance.java b/location/java/android/location/QzssAssistance.java new file mode 100644 index 000000000000..9383ce3c63b5 --- /dev/null +++ b/location/java/android/location/QzssAssistance.java @@ -0,0 +1,282 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.location.GnssAssistance.GnssSatelliteCorrections; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * A class contains QZSS assistance. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class QzssAssistance implements Parcelable { + + /** The QZSS almanac. */ + @Nullable private final GnssAlmanac mAlmanac; + + /** The Klobuchar ionospheric model. */ + @Nullable private final KlobucharIonosphericModel mIonosphericModel; + + /** The UTC model. */ + @Nullable private final UtcModel mUtcModel; + + /** The leap seconds model. */ + @Nullable private final LeapSecondsModel mLeapSecondsModel; + + /** The list of time models. */ + @NonNull private final List<TimeModel> mTimeModels; + + /** The list of QZSS ephemeris. */ + @NonNull private final List<QzssSatelliteEphemeris> mSatelliteEphemeris; + + /** The list of real time integrity models. */ + @NonNull private final List<RealTimeIntegrityModel> mRealTimeIntegrityModels; + + /** The list of QZSS satellite corrections. */ + @NonNull private final List<GnssSatelliteCorrections> mSatelliteCorrections; + + private QzssAssistance(Builder builder) { + mAlmanac = builder.mAlmanac; + mIonosphericModel = builder.mIonosphericModel; + mUtcModel = builder.mUtcModel; + mLeapSecondsModel = builder.mLeapSecondsModel; + if (builder.mTimeModels != null) { + mTimeModels = Collections.unmodifiableList(new ArrayList<>(builder.mTimeModels)); + } else { + mTimeModels = new ArrayList<>(); + } + if (builder.mSatelliteEphemeris != null) { + mSatelliteEphemeris = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteEphemeris)); + } else { + mSatelliteEphemeris = new ArrayList<>(); + } + if (builder.mRealTimeIntegrityModels != null) { + mRealTimeIntegrityModels = + Collections.unmodifiableList(new ArrayList<>(builder.mRealTimeIntegrityModels)); + } else { + mRealTimeIntegrityModels = new ArrayList<>(); + } + if (builder.mSatelliteCorrections != null) { + mSatelliteCorrections = + Collections.unmodifiableList(new ArrayList<>(builder.mSatelliteCorrections)); + } else { + mSatelliteCorrections = new ArrayList<>(); + } + } + + /** Returns the QZSS almanac. */ + @Nullable + public GnssAlmanac getAlmanac() { + return mAlmanac; + } + + /** Returns the Klobuchar ionospheric model. */ + @Nullable + public KlobucharIonosphericModel getIonosphericModel() { + return mIonosphericModel; + } + + /** Returns the UTC model. */ + @Nullable + public UtcModel getUtcModel() { + return mUtcModel; + } + + /** Returns the leap seconds model. */ + @Nullable + public LeapSecondsModel getLeapSecondsModel() { + return mLeapSecondsModel; + } + + /** Returns the list of time models. */ + @NonNull + public List<TimeModel> getTimeModels() { + return mTimeModels; + } + + /** Returns the list of QZSS ephemeris. */ + @NonNull + public List<QzssSatelliteEphemeris> getSatelliteEphemeris() { + return mSatelliteEphemeris; + } + + /** Returns the list of real time integrity models. */ + @NonNull + public List<RealTimeIntegrityModel> getRealTimeIntegrityModels() { + return mRealTimeIntegrityModels; + } + + /** Returns the list of QZSS satellite corrections. */ + @NonNull + public List<GnssSatelliteCorrections> getSatelliteCorrections() { + return mSatelliteCorrections; + } + + public static final @NonNull Creator<QzssAssistance> CREATOR = + new Creator<QzssAssistance>() { + @Override + @NonNull + public QzssAssistance createFromParcel(Parcel in) { + return new QzssAssistance.Builder() + .setAlmanac(in.readTypedObject(GnssAlmanac.CREATOR)) + .setIonosphericModel(in.readTypedObject(KlobucharIonosphericModel.CREATOR)) + .setUtcModel(in.readTypedObject(UtcModel.CREATOR)) + .setLeapSecondsModel(in.readTypedObject(LeapSecondsModel.CREATOR)) + .setTimeModels(in.createTypedArrayList(TimeModel.CREATOR)) + .setSatelliteEphemeris( + in.createTypedArrayList(QzssSatelliteEphemeris.CREATOR)) + .setRealTimeIntegrityModels( + in.createTypedArrayList(RealTimeIntegrityModel.CREATOR)) + .setSatelliteCorrections( + in.createTypedArrayList(GnssSatelliteCorrections.CREATOR)) + .build(); + } + @Override + public QzssAssistance[] newArray(int size) { + return new QzssAssistance[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedObject(mAlmanac, flags); + dest.writeTypedObject(mIonosphericModel, flags); + dest.writeTypedObject(mUtcModel, flags); + dest.writeTypedObject(mLeapSecondsModel, flags); + dest.writeTypedList(mTimeModels); + dest.writeTypedList(mSatelliteEphemeris); + dest.writeTypedList(mRealTimeIntegrityModels); + dest.writeTypedList(mSatelliteCorrections); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("QzssAssistance["); + builder.append("almanac = ").append(mAlmanac); + builder.append(", ionosphericModel = ").append(mIonosphericModel); + builder.append(", utcModel = ").append(mUtcModel); + builder.append(", leapSecondsModel = ").append(mLeapSecondsModel); + builder.append(", timeModels = ").append(mTimeModels); + builder.append(", satelliteEphemeris = ").append(mSatelliteEphemeris); + builder.append(", realTimeIntegrityModels = ").append(mRealTimeIntegrityModels); + builder.append(", satelliteCorrections = ").append(mSatelliteCorrections); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link QzssAssistance}. */ + public static final class Builder { + private GnssAlmanac mAlmanac; + private KlobucharIonosphericModel mIonosphericModel; + private UtcModel mUtcModel; + private LeapSecondsModel mLeapSecondsModel; + private List<TimeModel> mTimeModels; + private List<QzssSatelliteEphemeris> mSatelliteEphemeris; + private List<RealTimeIntegrityModel> mRealTimeIntegrityModels; + private List<GnssSatelliteCorrections> mSatelliteCorrections; + + /** Sets the QZSS almanac. */ + @NonNull + public Builder setAlmanac(@Nullable GnssAlmanac almanac) { + mAlmanac = almanac; + return this; + } + + /** Sets the Klobuchar ionospheric model. */ + @NonNull + public Builder setIonosphericModel(@Nullable KlobucharIonosphericModel ionosphericModel) { + mIonosphericModel = ionosphericModel; + return this; + } + + /** Sets the UTC model. */ + @NonNull + public Builder setUtcModel(@Nullable UtcModel utcModel) { + mUtcModel = utcModel; + return this; + } + + /** Sets the leap seconds model. */ + @NonNull + public Builder setLeapSecondsModel(@Nullable LeapSecondsModel leapSecondsModel) { + mLeapSecondsModel = leapSecondsModel; + return this; + } + + /** Sets the list of time models. */ + @NonNull + public Builder setTimeModels( + @Nullable @SuppressLint("NullableCollection") List<TimeModel> timeModels) { + mTimeModels = timeModels; + return this; + } + + /** Sets the list of QZSS ephemeris. */ + @NonNull + public Builder setSatelliteEphemeris( + @Nullable @SuppressLint("NullableCollection") + List<QzssSatelliteEphemeris> satelliteEphemeris) { + mSatelliteEphemeris = satelliteEphemeris; + return this; + } + + /** Sets the list of real time integrity model. */ + @NonNull + public Builder setRealTimeIntegrityModels( + @Nullable @SuppressLint("NullableCollection") + List<RealTimeIntegrityModel> realTimeIntegrityModels) { + mRealTimeIntegrityModels = realTimeIntegrityModels; + return this; + } + + /** Sets the list of QZSS satellite correction. */ + @NonNull + public Builder setSatelliteCorrections( + @Nullable @SuppressLint("NullableCollection") + List<GnssSatelliteCorrections> satelliteCorrections) { + mSatelliteCorrections = satelliteCorrections; + return this; + } + + /** Builds a {@link QzssAssistance} instance as specified by this builder. */ + @NonNull + public QzssAssistance build() { + return new QzssAssistance(this); + } + } +} diff --git a/location/java/android/location/QzssSatelliteEphemeris.java b/location/java/android/location/QzssSatelliteEphemeris.java new file mode 100644 index 000000000000..96203d9588c8 --- /dev/null +++ b/location/java/android/location/QzssSatelliteEphemeris.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.GpsSatelliteEphemeris.GpsL2Params; +import android.location.GpsSatelliteEphemeris.GpsSatelliteClockModel; +import android.location.GpsSatelliteEphemeris.GpsSatelliteHealth; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains ephemeris parameters specific to QZSS satellites. + * + * <p>This is defined in IS-QZSS-PNT section 4.1.2. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class QzssSatelliteEphemeris implements Parcelable { + /** Satellite PRN. */ + private final int mPrn; + + /** L2 parameters. */ + @NonNull private final GpsL2Params mGpsL2Params; + + /** Clock model. */ + @NonNull private final GpsSatelliteClockModel mSatelliteClockModel; + + /** Orbit model. */ + @NonNull private final KeplerianOrbitModel mSatelliteOrbitModel; + + /** Satellite health. */ + @NonNull private final GpsSatelliteHealth mSatelliteHealth; + + /** Ephemeris time. */ + @NonNull private final SatelliteEphemerisTime mSatelliteEphemerisTime; + + /** Returns the PRN of the satellite. */ + @IntRange(from = 183, to = 206) + public int getPrn() { + return mPrn; + } + + /** Returns the L2 parameters of the satellite. */ + @NonNull + public GpsL2Params getGpsL2Params() { + return mGpsL2Params; + } + + /** Returns the clock model of the satellite. */ + @NonNull + public GpsSatelliteClockModel getSatelliteClockModel() { + return mSatelliteClockModel; + } + + /** Returns the orbit model of the satellite. */ + @NonNull + public KeplerianOrbitModel getSatelliteOrbitModel() { + return mSatelliteOrbitModel; + } + + /** Returns the satellite health. */ + @NonNull + public GpsSatelliteHealth getSatelliteHealth() { + return mSatelliteHealth; + } + + /** Returns the ephemeris time. */ + @NonNull + public SatelliteEphemerisTime getSatelliteEphemerisTime() { + return mSatelliteEphemerisTime; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mPrn); + parcel.writeTypedObject(mGpsL2Params, flags); + parcel.writeTypedObject(mSatelliteClockModel, flags); + parcel.writeTypedObject(mSatelliteOrbitModel, flags); + parcel.writeTypedObject(mSatelliteHealth, flags); + parcel.writeTypedObject(mSatelliteEphemerisTime, flags); + } + + private QzssSatelliteEphemeris(Builder builder) { + // Allow PRN beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mPrn >= 1); + Preconditions.checkNotNull(builder.mGpsL2Params, "GpsL2Params cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteClockModel, + "SatelliteClockModel cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteOrbitModel, + "SatelliteOrbitModel cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteHealth, + "SatelliteHealth cannot be null"); + Preconditions.checkNotNull(builder.mSatelliteEphemerisTime, + "SatelliteEphemerisTime cannot be null"); + mPrn = builder.mPrn; + mGpsL2Params = builder.mGpsL2Params; + mSatelliteClockModel = builder.mSatelliteClockModel; + mSatelliteOrbitModel = builder.mSatelliteOrbitModel; + mSatelliteHealth = builder.mSatelliteHealth; + mSatelliteEphemerisTime = builder.mSatelliteEphemerisTime; + } + + public static final @NonNull Creator<QzssSatelliteEphemeris> CREATOR = + new Creator<QzssSatelliteEphemeris>() { + @Override + @NonNull + public QzssSatelliteEphemeris createFromParcel(Parcel in) { + final QzssSatelliteEphemeris.Builder qzssSatelliteEphemeris = + new Builder() + .setPrn(in.readInt()) + .setGpsL2Params(in.readTypedObject(GpsL2Params.CREATOR)) + .setSatelliteClockModel( + in.readTypedObject(GpsSatelliteClockModel.CREATOR)) + .setSatelliteOrbitModel( + in.readTypedObject(KeplerianOrbitModel.CREATOR)) + .setSatelliteHealth( + in.readTypedObject(GpsSatelliteHealth.CREATOR)) + .setSatelliteEphemerisTime( + in.readTypedObject(SatelliteEphemerisTime.CREATOR)); + return qzssSatelliteEphemeris.build(); + } + + @Override + public QzssSatelliteEphemeris[] newArray(int size) { + return new QzssSatelliteEphemeris[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("QzssSatelliteEphemeris["); + builder.append("prn=").append(mPrn); + builder.append(", gpsL2Params=").append(mGpsL2Params); + builder.append(", satelliteClockModel=").append(mSatelliteClockModel); + builder.append(", satelliteOrbitModel=").append(mSatelliteOrbitModel); + builder.append(", satelliteHealth=").append(mSatelliteHealth); + builder.append(", satelliteEphemerisTime=").append(mSatelliteEphemerisTime); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link QzssSatelliteEphemeris}. */ + public static final class Builder { + private int mPrn; + private GpsL2Params mGpsL2Params; + private GpsSatelliteClockModel mSatelliteClockModel; + private KeplerianOrbitModel mSatelliteOrbitModel; + private GpsSatelliteHealth mSatelliteHealth; + private SatelliteEphemerisTime mSatelliteEphemerisTime; + + /** Sets the PRN of the satellite. */ + @NonNull + public Builder setPrn(@IntRange(from = 183, to = 206) int prn) { + mPrn = prn; + return this; + } + + /** Sets the L2 parameters of the satellite. */ + @NonNull + public Builder setGpsL2Params(@NonNull GpsL2Params gpsL2Params) { + mGpsL2Params = gpsL2Params; + return this; + } + + /** Sets the clock model of the satellite. */ + @NonNull + public Builder setSatelliteClockModel(@NonNull GpsSatelliteClockModel satelliteClockModel) { + mSatelliteClockModel = satelliteClockModel; + return this; + } + + /** Sets the orbit model of the satellite. */ + @NonNull + public Builder setSatelliteOrbitModel(@NonNull KeplerianOrbitModel satelliteOrbitModel) { + mSatelliteOrbitModel = satelliteOrbitModel; + return this; + } + + /** Sets the satellite health. */ + @NonNull + public Builder setSatelliteHealth(@NonNull GpsSatelliteHealth satelliteHealth) { + mSatelliteHealth = satelliteHealth; + return this; + } + + /** Sets the ephemeris time. */ + @NonNull + public Builder setSatelliteEphemerisTime( + @NonNull SatelliteEphemerisTime satelliteEphemerisTime) { + mSatelliteEphemerisTime = satelliteEphemerisTime; + return this; + } + + /** Builds a {@link QzssSatelliteEphemeris} instance as specified by this builder. */ + @NonNull + public QzssSatelliteEphemeris build() { + return new QzssSatelliteEphemeris(this); + } + } +} diff --git a/location/java/android/location/RealTimeIntegrityModel.java b/location/java/android/location/RealTimeIntegrityModel.java new file mode 100644 index 000000000000..d268926e56e2 --- /dev/null +++ b/location/java/android/location/RealTimeIntegrityModel.java @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains the real time integrity status of a GNSS satellite based on notice advisory. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class RealTimeIntegrityModel implements Parcelable { + /** + * Pseudo-random or satellite ID number for the satellite, + * a.k.a. Space Vehicle (SV), or OSN number for Glonass. + * + * <p>The distinction is made by looking at the constellation field. Values + * must be in the range of: + * + * <p> - GPS: 1-32 + * <p> - GLONASS: 1-25 + * <p> - QZSS: 183-206 + * <p> - Galileo: 1-36 + * <p> - Beidou: 1-63 + */ + private final int mSvid; + + /** Indicates whether the satellite is currently usable for navigation. */ + private final boolean mUsable; + + /** UTC timestamp (in seconds) when the advisory was published. */ + private final long mPublishDateSeconds; + + /** UTC timestamp (in seconds) for the start of the event. */ + private final long mStartDateSeconds; + + /** UTC timestamp (in seconds) for the end of the event. */ + private final long mEndDateSeconds; + + /** + * Abbreviated type of the advisory, providing a concise summary of the event. + * + * <p>This field follows different definitions depending on the GNSS constellation: + * <p> - GPS: See NANU type definitions(https://www.navcen.uscg.gov/nanu-abbreviations-and-descriptions) + * <p> - Galileo: See NAGU type definitions(https://www.gsc-europa.eu/system-service-status/nagu-information) + * <p> - QZSS: See NAQU type definitions](https://sys.qzss.go.jp/dod/en/naqu/type.html) + * <p> - BeiDou: Not used; set to an empty string. + */ + @NonNull private final String mAdvisoryType; + + /** + * Unique identifier for the advisory within its constellation's system. + * + * <p>For BeiDou, this is not used and should be an empty string. + */ + @NonNull private final String mAdvisoryNumber; + + private RealTimeIntegrityModel(Builder builder) { + // Allow SV ID beyond the range to support potential future extensibility. + Preconditions.checkArgument(builder.mSvid >= 1); + Preconditions.checkArgument(builder.mPublishDateSeconds > 0); + Preconditions.checkArgument(builder.mStartDateSeconds > 0); + Preconditions.checkArgument(builder.mEndDateSeconds > 0); + Preconditions.checkNotNull(builder.mAdvisoryType, "AdvisoryType cannot be null"); + Preconditions.checkNotNull(builder.mAdvisoryNumber, "AdvisoryNumber cannot be null"); + mSvid = builder.mSvid; + mUsable = builder.mUsable; + mPublishDateSeconds = builder.mPublishDateSeconds; + mStartDateSeconds = builder.mStartDateSeconds; + mEndDateSeconds = builder.mEndDateSeconds; + mAdvisoryType = builder.mAdvisoryType; + mAdvisoryNumber = builder.mAdvisoryNumber; + } + + /** + * Returns the Pseudo-random or satellite ID number for the satellite, + * a.k.a. Space Vehicle (SV), or OSN number for Glonass. + * + * <p>The distinction is made by looking at the constellation field. Values + * must be in the range of: + * + * <p> - GPS: 1-32 + * <p> - GLONASS: 1-25 + * <p> - QZSS: 183-206 + * <p> - Galileo: 1-36 + * <p> - Beidou: 1-63 + */ + @IntRange(from = 1, to = 206) + public int getSvid() { + return mSvid; + } + + /** Returns whether the satellite is usable or not. */ + public boolean isUsable() { + return mUsable; + } + + /** Returns the UTC timestamp (in seconds) when the advisory was published */ + @IntRange(from = 0) + public long getPublishDateSeconds() { + return mPublishDateSeconds; + } + + /** Returns UTC timestamp (in seconds) for the start of the event. */ + @IntRange(from = 0) + public long getStartDateSeconds() { + return mStartDateSeconds; + } + + /** Returns UTC timestamp (in seconds) for the end of the event. */ + @IntRange(from = 0) + public long getEndDateSeconds() { + return mEndDateSeconds; + } + + /** Returns the abbreviated type of notice advisory. */ + @NonNull + public String getAdvisoryType() { + return mAdvisoryType; + } + + /** Returns the unique identifier for the advisory. */ + @NonNull + public String getAdvisoryNumber() { + return mAdvisoryNumber; + } + + public static final @NonNull Creator<RealTimeIntegrityModel> CREATOR = + new Creator<RealTimeIntegrityModel>() { + @Override + @NonNull + public RealTimeIntegrityModel createFromParcel(Parcel in) { + RealTimeIntegrityModel realTimeIntegrityModel = + new RealTimeIntegrityModel.Builder() + .setSvid(in.readInt()) + .setUsable(in.readBoolean()) + .setPublishDateSeconds(in.readLong()) + .setStartDateSeconds(in.readLong()) + .setEndDateSeconds(in.readLong()) + .setAdvisoryType(in.readString8()) + .setAdvisoryNumber(in.readString8()) + .build(); + return realTimeIntegrityModel; + } + + @Override + public RealTimeIntegrityModel[] newArray(int size) { + return new RealTimeIntegrityModel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mSvid); + parcel.writeBoolean(mUsable); + parcel.writeLong(mPublishDateSeconds); + parcel.writeLong(mStartDateSeconds); + parcel.writeLong(mEndDateSeconds); + parcel.writeString8(mAdvisoryType); + parcel.writeString8(mAdvisoryNumber); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("RealTimeIntegrityModel["); + builder.append("svid = ").append(mSvid); + builder.append(", usable = ").append(mUsable); + builder.append(", publishDateSeconds = ").append(mPublishDateSeconds); + builder.append(", startDateSeconds = ").append(mStartDateSeconds); + builder.append(", endDateSeconds = ").append(mEndDateSeconds); + builder.append(", advisoryType = ").append(mAdvisoryType); + builder.append(", advisoryNumber = ").append(mAdvisoryNumber); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link RealTimeIntegrityModel} */ + public static final class Builder { + private int mSvid; + private boolean mUsable; + private long mPublishDateSeconds; + private long mStartDateSeconds; + private long mEndDateSeconds; + private String mAdvisoryType; + private String mAdvisoryNumber; + + /** + * Sets the Pseudo-random or satellite ID number for the satellite, + * a.k.a. Space Vehicle (SV), or OSN number for Glonass. + * + * <p>The distinction is made by looking at the constellation field. Values + * must be in the range of: + * + * <p> - GPS: 1-32 + * <p> - GLONASS: 1-25 + * <p> - QZSS: 183-206 + * <p> - Galileo: 1-36 + * <p> - Beidou: 1-63 + */ + @NonNull + public Builder setSvid(@IntRange(from = 1, to = 206) int svid) { + mSvid = svid; + return this; + } + + /** Sets whether the satellite is usable or not. */ + @NonNull + public Builder setUsable(boolean usable) { + mUsable = usable; + return this; + } + + /** Sets the UTC timestamp (in seconds) when the advisory was published. */ + @NonNull + public Builder setPublishDateSeconds(@IntRange(from = 0) long publishDateSeconds) { + mPublishDateSeconds = publishDateSeconds; + return this; + } + + /** Sets the UTC timestamp (in seconds) for the start of the event. */ + @NonNull + public Builder setStartDateSeconds(@IntRange(from = 0) long startDateSeconds) { + mStartDateSeconds = startDateSeconds; + return this; + } + + /** Sets the UTC timestamp (in seconds) for the end of the event. */ + @NonNull + public Builder setEndDateSeconds(@IntRange(from = 0) long endDateSeconds) { + mEndDateSeconds = endDateSeconds; + return this; + } + + /** Sets the abbreviated type of notice advisory. */ + @NonNull + public Builder setAdvisoryType(@NonNull String advisoryType) { + mAdvisoryType = advisoryType; + return this; + } + + /** Sets the unique identifier for the advisory. */ + @NonNull + public Builder setAdvisoryNumber(@NonNull String advisoryNumber) { + mAdvisoryNumber = advisoryNumber; + return this; + } + + /** Builds a {@link RealTimeIntegrityModel} instance as specified by this builder. */ + @NonNull + public RealTimeIntegrityModel build() { + return new RealTimeIntegrityModel(this); + } + } +} diff --git a/location/java/android/location/SatelliteEphemerisTime.java b/location/java/android/location/SatelliteEphemerisTime.java new file mode 100644 index 000000000000..0ab3acfe3147 --- /dev/null +++ b/location/java/android/location/SatelliteEphemerisTime.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains time of ephemeris for GPS, Galileo, and QZSS. + * + * <p>For GPS, this is defined in IS-GPS-200, section 20.3.3.4.1. + * <p>For Galileo, this is defined in Galileo-OS-SIS-ICD, section 5.1.2, 5.1.9.2. + * <p>For QZSS, this is defined in IS-QZSS-200, section 4.1.2.4. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class SatelliteEphemerisTime implements Parcelable { + /** The issue of ephemeris data. */ + private final int mIode; + + /** The satellite week number without rollover. */ + private final int mWeekNumber; + + /** The broadcast time of ephemeris in GNSS time of week in seconds. */ + private final int mToeSeconds; + + private SatelliteEphemerisTime(Builder builder) { + Preconditions.checkArgumentInRange(builder.mIode, 0, 1023, "Iode"); + Preconditions.checkArgument(builder.mWeekNumber >= 0); + Preconditions.checkArgumentInRange(builder.mToeSeconds, 0, 604799, "ToeSeconds"); + mIode = builder.mIode; + mWeekNumber = builder.mWeekNumber; + mToeSeconds = builder.mToeSeconds; + } + + /** Returns the issue of ephemeris data. */ + @IntRange(from = 0, to = 1023) + public int getIode() { + return mIode; + } + + /** Returns the satellite week number without rollover. */ + @IntRange(from = 0) + public int getWeekNumber() { + return mWeekNumber; + } + + /** Returns the broadcast time of ephemeris in GNSS time of week in seconds. */ + @IntRange(from = 0, to = 604799) + public int getToeSeconds() { + return mToeSeconds; + } + + public static final @NonNull Creator<SatelliteEphemerisTime> CREATOR = + new Creator<SatelliteEphemerisTime>() { + @Override + public SatelliteEphemerisTime createFromParcel(Parcel in) { + final SatelliteEphemerisTime.Builder satelliteEphemerisTime = + new Builder() + .setIode(in.readInt()) + .setWeekNumber(in.readInt()) + .setToeSeconds(in.readInt()); + return satelliteEphemerisTime.build(); + } + + @Override + public SatelliteEphemerisTime[] newArray(int size) { + return new SatelliteEphemerisTime[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int flags) { + parcel.writeInt(mIode); + parcel.writeInt(mWeekNumber); + parcel.writeInt(mToeSeconds); + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("SatelliteEphemerisTime["); + builder.append("iode = ").append(mIode); + builder.append(", weekNumber = ").append(mWeekNumber); + builder.append(", toeSeconds = ").append(mToeSeconds); + builder.append("]"); + return builder.toString(); + } + + /** Builder for {@link SatelliteEphemerisTime}. */ + public static final class Builder { + private int mIode; + private int mWeekNumber; + private int mToeSeconds; + + /** Sets the issue of ephemeris data. */ + @NonNull + public Builder setIode(@IntRange(from = 0, to = 1023) int iode) { + mIode = iode; + return this; + } + + /** Sets the satellite week number without rollover. */ + @NonNull + public Builder setWeekNumber(@IntRange(from = 0) int weekNumber) { + mWeekNumber = weekNumber; + return this; + } + + /** Sets the broadcast time of ephemeris in GNSS time of week in seconds. */ + @NonNull + public Builder setToeSeconds(@IntRange(from = 0, to = 604799) int toeSeconds) { + mToeSeconds = toeSeconds; + return this; + } + + /** Builds a {@link SatelliteEphemerisTime} instance as specified by this builder. */ + @NonNull + public SatelliteEphemerisTime build() { + return new SatelliteEphemerisTime(this); + } + } +} diff --git a/location/java/android/location/TimeModel.java b/location/java/android/location/TimeModel.java new file mode 100644 index 000000000000..380f7b87d8f6 --- /dev/null +++ b/location/java/android/location/TimeModel.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.GnssStatus.ConstellationType; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains the GNSS-GNSS system time offset between the GNSS system time. + * + * <p>This is defined in IS-GPS-200 section 30.3.3.8.2. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class TimeModel implements Parcelable { + /* + * Model represents parameters to convert from current GNSS to GNSS system + * time indicated by toGnss. + */ + private final @ConstellationType int mToGnss; + + /** Bias coefficient of GNSS time scale relative to GNSS time scale in seconds. */ + private final double mA0; + + /** Drift coefficient of GNSS time scale relative to GNSS time scale in seconds per second. */ + private final double mA1; + + /** GNSS time of week in seconds. */ + private final int mTimeOfWeek; + + /** Week number of the GNSS time. */ + private final int mWeekNumber; + + private TimeModel(Builder builder) { + Preconditions.checkArgumentInRange( + builder.mToGnss, + GnssStatus.CONSTELLATION_UNKNOWN, + GnssStatus.CONSTELLATION_COUNT, + "ToGnss"); + Preconditions.checkArgumentInRange(builder.mA0, -1.0f, 1.0f, "A0"); + Preconditions.checkArgumentInRange(builder.mA1, -3.28e-6f, 3.28e-6f, "A1"); + Preconditions.checkArgumentInRange(builder.mTimeOfWeek, 0, 604800, "TimeOfWeek"); + Preconditions.checkArgument(builder.mWeekNumber >= 0); + mToGnss = builder.mToGnss; + mA0 = builder.mA0; + mA1 = builder.mA1; + mTimeOfWeek = builder.mTimeOfWeek; + mWeekNumber = builder.mWeekNumber; + } + + /** Returns the constellation type to convert from current GNSS system time. */ + @ConstellationType + public int getToGnss() { + return mToGnss; + } + + /** Returns the bias coefficient of GNSS time scale relative to GNSS time scale in seconds. */ + @FloatRange(from = -1.0f, to = 1.0f) + public double getA0() { + return mA0; + } + + /** + * Returns the drift coefficient of GNSS time scale relative to GNSS time scale in seconds per + * second. + */ + @FloatRange(from = -3.28e-6f, to = 3.28e-6f) + public double getA1() { + return mA1; + } + + /** Returns the GNSS time of week in seconds. */ + @IntRange(from = 0, to = 604800) + public int getTimeOfWeek() { + return mTimeOfWeek; + } + + /** Returns the week number of the GNSS time. */ + @IntRange(from = 0) + public int getWeekNumber() { + return mWeekNumber; + } + + public static final @NonNull Creator<TimeModel> CREATOR = + new Creator<TimeModel>() { + @Override + public TimeModel createFromParcel(@NonNull Parcel source) { + return new TimeModel.Builder() + .setToGnss(source.readInt()) + .setA0(source.readDouble()) + .setA1(source.readDouble()) + .setTimeOfWeek(source.readInt()) + .setWeekNumber(source.readInt()) + .build(); + } + + @Override + public TimeModel[] newArray(int size) { + return new TimeModel[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("TimeModel["); + builder.append("toGnss = ").append(mToGnss); + builder.append(", a0 = ").append(mA0); + builder.append(", a1 = ").append(mA1); + builder.append(", timeOfWeek = ").append(mTimeOfWeek); + builder.append(", weekNumber = ").append(mWeekNumber); + builder.append("]"); + return builder.toString(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mToGnss); + dest.writeDouble(mA0); + dest.writeDouble(mA1); + dest.writeInt(mTimeOfWeek); + dest.writeInt(mWeekNumber); + } + + /** Builder for {@link TimeModel} */ + public static final class Builder { + + private @ConstellationType int mToGnss; + private double mA0; + private double mA1; + private int mTimeOfWeek; + private int mWeekNumber; + + /** Sets the constellation type to convert from current GNSS system time. */ + @NonNull + public Builder setToGnss(@ConstellationType int toGnss) { + mToGnss = toGnss; + return this; + } + + /** Sets the bias coefficient of GNSS time scale relative to GNSS time scale in seconds. */ + @NonNull + public Builder setA0(@FloatRange(from = -1.0f, to = 1.0f) double a0) { + mA0 = a0; + return this; + } + + /** + * Sets the drift coefficient of GNSS time scale relative to GNSS time scale in seconds per + * second. + */ + @NonNull + public Builder setA1(@FloatRange(from = -3.28e-6f, to = 3.28e-6f) double a1) { + mA1 = a1; + return this; + } + + /** Sets the GNSS time of week in seconds. */ + @NonNull + public Builder setTimeOfWeek(@IntRange(from = 0, to = 604800) int timeOfWeek) { + mTimeOfWeek = timeOfWeek; + return this; + } + + /** Sets the week number of the GNSS time. */ + @NonNull + public Builder setWeekNumber(@IntRange(from = 0) int weekNumber) { + mWeekNumber = weekNumber; + return this; + } + + /** Builds the {@link TimeModel} object. */ + @NonNull + public TimeModel build() { + return new TimeModel(this); + } + } +} diff --git a/location/java/android/location/UtcModel.java b/location/java/android/location/UtcModel.java new file mode 100644 index 000000000000..6dc633de3fcb --- /dev/null +++ b/location/java/android/location/UtcModel.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.location; + +import android.annotation.FlaggedApi; +import android.annotation.FloatRange; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.location.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Preconditions; + +/** + * A class contains parameters to convert from current GNSS time to UTC time. + * + * <p>This is defined in RINEX 3.05 "TIME SYSTEM CORR" in table A5. + * + * @hide + */ +@FlaggedApi(Flags.FLAG_GNSS_ASSISTANCE_INTERFACE) +@SystemApi +public final class UtcModel implements Parcelable { + /** Bias coefficient of GNSS time scale relative to UTC time scale in seconds. */ + private final double mA0; + + /** Drift coefficient of GNSS time scale relative to UTC time scale in seconds per second. */ + private final double mA1; + + /** Reference GNSS time of week in seconds. */ + private final int mTimeOfWeek; + + /** Reference GNSS week number. */ + private final int mWeekNumber; + + private UtcModel(Builder builder) { + Preconditions.checkArgumentInRange(builder.mA0, -2.0f, 2.0f, "A0"); + Preconditions.checkArgumentInRange(builder.mA1, -7.45e-9f, 7.45e-9f, "A1"); + Preconditions.checkArgumentInRange(builder.mTimeOfWeek, 0, 604800, "TimeOfWeek"); + Preconditions.checkArgument(builder.mWeekNumber >= 0); + mA0 = builder.mA0; + mA1 = builder.mA1; + mTimeOfWeek = builder.mTimeOfWeek; + mWeekNumber = builder.mWeekNumber; + } + + /** Returns the bias coefficient of GNSS time scale relative to UTC time scale in seconds. */ + @FloatRange(from = -2.0f, to = 2.0f) + public double getA0() { + return mA0; + } + + /** + * Returns the drift coefficient of GNSS time scale relative to UTC time scale in seconds per + * second. + */ + @FloatRange(from = -7.45e-9f, to = 7.45e-9f) + public double getA1() { + return mA1; + } + + /** Returns the reference GNSS time of week in seconds. */ + @IntRange(from = 0, to = 604800) + public int getTimeOfWeek() { + return mTimeOfWeek; + } + + /** Returns the reference GNSS week number. */ + @IntRange(from = 0) + public int getWeekNumber() { + return mWeekNumber; + } + + @Override + public int describeContents() { + return 0; + } + @Override + @NonNull + public String toString() { + StringBuilder builder = new StringBuilder("UtcModel["); + builder.append("a0 = ").append(mA0); + builder.append(", a1 = ").append(mA1); + builder.append(", timeOfWeek = ").append(mTimeOfWeek); + builder.append(", weekNumber = ").append(mWeekNumber); + builder.append("]"); + return builder.toString(); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeDouble(mA0); + dest.writeDouble(mA1); + dest.writeInt(mTimeOfWeek); + dest.writeInt(mWeekNumber); + } + + public static final @NonNull Creator<UtcModel> CREATOR = + new Creator<UtcModel>() { + @Override + public UtcModel createFromParcel(@NonNull Parcel source) { + return new UtcModel.Builder() + .setA0(source.readDouble()) + .setA1(source.readDouble()) + .setTimeOfWeek(source.readInt()) + .setWeekNumber(source.readInt()) + .build(); + } + + @Override + public UtcModel[] newArray(int size) { + return new UtcModel[size]; + } + }; + + /** Builder for {@link UtcModel}. */ + public static final class Builder { + private double mA0; + private double mA1; + private int mTimeOfWeek; + private int mWeekNumber; + + /** Sets the bias coefficient of GNSS time scale relative to UTC time scale in seconds. */ + @NonNull + public Builder setA0(@FloatRange(from = -2.0f, to = 2.0f) double a0) { + mA0 = a0; + return this; + } + + /** + * Sets the drift coefficient of GNSS time scale relative to UTC time scale in seconds per + * second. + */ + @NonNull + public Builder setA1(@FloatRange(from = -7.45e-9f, to = 7.45e-9f) double a1) { + mA1 = a1; + return this; + } + + /** Sets the reference GNSS time of week in seconds. */ + @NonNull + public Builder setTimeOfWeek(@IntRange(from = 0, to = 604800) int timeOfWeek) { + mTimeOfWeek = timeOfWeek; + return this; + } + + /** Sets the reference GNSS week number. */ + @NonNull + public Builder setWeekNumber(@IntRange(from = 0) int weekNumber) { + mWeekNumber = weekNumber; + return this; + } + + /** Builds a {@link UtcModel} instance as specified by this builder. */ + @NonNull + public UtcModel build() { + return new UtcModel(this); + } + } +} diff --git a/location/java/android/location/flags/location.aconfig b/location/java/android/location/flags/location.aconfig index 5395206155b3..c02cc808d60c 100644 --- a/location/java/android/location/flags/location.aconfig +++ b/location/java/android/location/flags/location.aconfig @@ -161,3 +161,10 @@ flag { description: "Flag for gating the density-based coarse locations" bug: "376198890" } + +flag { + name: "gnss_assistance_interface" + namespace: "location" + description: "Flag for GNSS assistance interface" + bug: "209078566" +}
\ No newline at end of file diff --git a/nfc/Android.bp b/nfc/Android.bp index 7ad8c4c8de41..abe0ab757ba6 100644 --- a/nfc/Android.bp +++ b/nfc/Android.bp @@ -37,6 +37,7 @@ filegroup { java_sdk_library { name: "framework-nfc", libs: [ + "androidx.annotation_annotation", "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage "framework-permission-s.stubs.module_lib", "framework-permission.stubs.module_lib", diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index e97b15d3b926..cf11ac028858 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -85,6 +85,10 @@ package android.nfc { field public static final int HCE_ACTIVATE = 1; // 0x1 field public static final int HCE_DATA_TRANSFERRED = 2; // 0x2 field public static final int HCE_DEACTIVATE = 3; // 0x3 + field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int NFCEE_TECH_A = 1; // 0x1 + field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int NFCEE_TECH_B = 2; // 0x2 + field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int NFCEE_TECH_F = 4; // 0x4 + field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int NFCEE_TECH_NONE = 0; // 0x0 field public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2; // 0x2 field public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1; // 0x1 field public static final int STATUS_OK = 0; // 0x0 @@ -250,6 +254,7 @@ package android.nfc.cardemulation { field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID = 1; // 0x1 field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3; // 0x3 field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_SUCCESS = 0; // 0x0 + field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_UNKNOWN = -1; // 0xffffffff } } diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index fb11875ec7d7..b46e34368e77 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -150,28 +150,24 @@ public final class NfcOemExtension { /** * Technology Type for {@link #getActiveNfceeList()}. - * @hide */ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) public static final int NFCEE_TECH_NONE = 0; /** * Technology Type for {@link #getActiveNfceeList()}. - * @hide */ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) public static final int NFCEE_TECH_A = 1; /** * Technology Type for {@link #getActiveNfceeList()}. - * @hide */ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) public static final int NFCEE_TECH_B = 1 << 1; /** * Technology Type for {@link #getActiveNfceeList()}. - * @hide */ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) public static final int NFCEE_TECH_F = 1 << 2; @@ -670,12 +666,15 @@ public final class NfcOemExtension { /** * Get the Active NFCEE (NFC Execution Environment) List * - * @see Reader#getName() for the list of possible NFCEE names. - * * @return Map< String, @NfceeTechnology Integer > * A HashMap where keys are activated secure elements and - * the values are bitmap of technologies supported by each secure element - * on success keys can contain "eSE" and "UICC", otherwise empty map. + * the values are bitmap of technologies supported by each secure element: + * NFCEE_TECH_A == 0x1 + * NFCEE_TECH_B == 0x2 + * NFCEE_TECH_F == 0x4 + * and keys can contain "eSE" and "SIM" with a number, + * in case of failure an empty map is returned. + * @see Reader#getName() for the list of possible NFCEE names. */ @NonNull @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java index 803770218299..e0bc15fe6e94 100644 --- a/nfc/java/android/nfc/cardemulation/CardEmulation.java +++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java @@ -1114,6 +1114,14 @@ public final class CardEmulation { @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3; + /** + * Setting the default subscription ID failed because of unknown error. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_ENABLE_CARD_EMULATION_EUICC) + public static final int SET_SUBSCRIPTION_ID_STATUS_UNKNOWN = -1; + /** @hide */ @IntDef(prefix = "SET_SUBSCRIPTION_ID_STATUS_", value = { @@ -1121,6 +1129,7 @@ public final class CardEmulation { SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID, SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR, SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED, + SET_SUBSCRIPTION_ID_STATUS_UNKNOWN }) @Retention(RetentionPolicy.SOURCE) public @interface SetSubscriptionIdStatus {} @@ -1129,9 +1138,10 @@ public final class CardEmulation { * Sets the system's default NFC subscription id. * * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this sets the - * default UICC NFCEE that will handle NFC offhost CE transactoions </p> + * default UICC NFCEE that will handle NFC offhost CE transactions </p> * - * @param subscriptionId the default NFC subscription Id to set. + * @param subscriptionId the default NFC subscription Id to set. User can get subscription id + * from {@link SubscriptionManager#getSubscriptionId(int)} * @return status of the operation. * * @throws UnsupportedOperationException If the device does not have @@ -1153,7 +1163,7 @@ public final class CardEmulation { * Returns the system's default NFC subscription id. * * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this returns the - * default UICC NFCEE that will handle NFC offhost CE transactoions </p> + * default UICC NFCEE that will handle NFC offhost CE transactions </p> * <p> If the device has no UICC that can serve as NFCEE, this will return * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.</p> * diff --git a/nfc/tests/Android.bp b/nfc/tests/Android.bp index bfa814d149f0..b6090e853158 100644 --- a/nfc/tests/Android.bp +++ b/nfc/tests/Android.bp @@ -25,17 +25,36 @@ package { android_test { name: "NfcManagerTests", static_libs: [ - "androidx.test.ext.junit", + "androidx.test.core", "androidx.test.rules", - "mockito-target-minus-junit4", + "androidx.test.runner", + "androidx.test.ext.junit", + "framework-nfc.impl", + "mockito-target-extended-minus-junit4", + "frameworks-base-testutils", "truth", + "androidx.annotation_annotation", + "androidx.appcompat_appcompat", + "flag-junit", + "platform-test-annotations", + "testables", ], libs: [ - "framework-nfc.impl", + "android.test.base.stubs.system", + "android.test.mock.stubs.system", "android.test.runner.stubs.system", ], + jni_libs: [ + // Required for ExtendedMockito + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], srcs: ["src/**/*.java"], platform_apis: true, certificate: "platform", - test_suites: ["device-tests"], + test_suites: [ + "device-tests", + "mts-nfc", + ], + min_sdk_version: "35", // Should be 36 later. } diff --git a/nfc/tests/AndroidManifest.xml b/nfc/tests/AndroidManifest.xml index 99e2c34c656b..95646720d3d5 100644 --- a/nfc/tests/AndroidManifest.xml +++ b/nfc/tests/AndroidManifest.xml @@ -17,7 +17,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.nfc"> - <application> + <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> </application> diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp index 43d8a628837b..1a3446ec56de 100644 --- a/packages/CrashRecovery/framework/Android.bp +++ b/packages/CrashRecovery/framework/Android.bp @@ -14,7 +14,11 @@ java_sdk_library { name: "framework-platformcrashrecovery", srcs: [":framework-crashrecovery-sources"], defaults: ["framework-non-updatable-unbundled-defaults"], - permitted_packages: ["android.service.watchdog"], + permitted_packages: [ + "android.service.watchdog", + "android.crashrecovery", + ], + static_libs: ["android.crashrecovery.flags-aconfig-java"], aidl: { include_dirs: [ "frameworks/base/core/java", diff --git a/packages/CrashRecovery/framework/api/system-current.txt b/packages/CrashRecovery/framework/api/system-current.txt index 3a48a4ab02f2..68429ea4297d 100644 --- a/packages/CrashRecovery/framework/api/system-current.txt +++ b/packages/CrashRecovery/framework/api/system-current.txt @@ -9,7 +9,9 @@ package android.service.watchdog { method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages(); method @NonNull public abstract java.util.List<android.service.watchdog.ExplicitHealthCheckService.PackageConfig> onGetSupportedPackages(); method public abstract void onRequestHealthCheck(@NonNull String); + method @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public final void setHealthCheckResultCallback(@Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<android.os.Bundle>); field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"; + field @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public static final String EXTRA_HEALTH_CHECK_PASSED_PACKAGE = "android.service.watchdog.extra.HEALTH_CHECK_PASSED_PACKAGE"; field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService"; } diff --git a/packages/CrashRecovery/framework/api/test-current.txt b/packages/CrashRecovery/framework/api/test-current.txt index 54f501faa250..d802177e249b 100644 --- a/packages/CrashRecovery/framework/api/test-current.txt +++ b/packages/CrashRecovery/framework/api/test-current.txt @@ -1,9 +1 @@ // Signature format: 2.0 -package android.service.watchdog { - - public abstract class ExplicitHealthCheckService extends android.app.Service { - method public void setCallback(@Nullable android.os.RemoteCallback); - } - -} - diff --git a/packages/CrashRecovery/framework/java/android/service/watchdog/ExplicitHealthCheckService.java b/packages/CrashRecovery/framework/java/android/service/watchdog/ExplicitHealthCheckService.java index 7befbfb0f370..b03e37600bbb 100644 --- a/packages/CrashRecovery/framework/java/android/service/watchdog/ExplicitHealthCheckService.java +++ b/packages/CrashRecovery/framework/java/android/service/watchdog/ExplicitHealthCheckService.java @@ -18,15 +18,17 @@ package android.service.watchdog; import static android.os.Parcelable.Creator; +import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.TestApi; import android.app.Service; import android.content.Intent; import android.content.pm.PackageManager; +import android.crashrecovery.flags.Flags; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -42,7 +44,9 @@ import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; /** * A service to provide packages supporting explicit health checks and route checks to these @@ -89,11 +93,10 @@ public abstract class ExplicitHealthCheckService extends Service { /** * {@link Bundle} key for a {@link String} value. - * - * {@hide} */ + @FlaggedApi(Flags.FLAG_ENABLE_CRASHRECOVERY) public static final String EXTRA_HEALTH_CHECK_PASSED_PACKAGE = - "android.service.watchdog.extra.health_check_passed_package"; + "android.service.watchdog.extra.HEALTH_CHECK_PASSED_PACKAGE"; /** * The Intent action that a service must respond to. Add it to the intent filter of the service @@ -152,7 +155,8 @@ public abstract class ExplicitHealthCheckService extends Service { @NonNull public abstract List<String> onGetRequestedPackages(); private final Handler mHandler = Handler.createAsync(Looper.getMainLooper()); - @Nullable private RemoteCallback mCallback; + @Nullable private Consumer<Bundle> mHealthCheckResultCallback; + @Nullable private Executor mCallbackExecutor; @Override @NonNull @@ -161,30 +165,49 @@ public abstract class ExplicitHealthCheckService extends Service { } /** - * Sets {@link RemoteCallback}, for testing purpose. + * Sets a callback to be invoked when an explicit health check passes for a package. + * <p> + * The callback will receive a {@link Bundle} containing the package name that passed the + * health check, identified by the key {@link #EXTRA_HEALTH_CHECK_PASSED_PACKAGE}. + * <p> + * <b>Note:</b> This API is primarily intended for testing purposes. Calling this outside of a + * test environment will override the default callback mechanism used to notify the system + * about health check results. Use with caution in production code. * - * @hide + * @param executor The executor on which the callback should be invoked. If {@code null}, the + * callback will be executed on the main thread. + * @param callback A callback that receives a {@link Bundle} containing the package name that + * passed the health check. */ - @TestApi - public void setCallback(@Nullable RemoteCallback callback) { - mCallback = callback; + @FlaggedApi(Flags.FLAG_ENABLE_CRASHRECOVERY) + public final void setHealthCheckResultCallback(@CallbackExecutor @Nullable Executor executor, + @Nullable Consumer<Bundle> callback) { + mCallbackExecutor = executor; + mHealthCheckResultCallback = callback; } + + private void executeCallback(@NonNull String packageName) { + if (mHealthCheckResultCallback != null) { + Objects.requireNonNull(packageName, + "Package passing explicit health check must be non-null"); + Bundle bundle = new Bundle(); + bundle.putString(EXTRA_HEALTH_CHECK_PASSED_PACKAGE, packageName); + mHealthCheckResultCallback.accept(bundle); + } else { + Log.wtf(TAG, "System missed explicit health check result for " + packageName); + } + } + /** * Implementors should call this to notify the system when explicit health check passes * for {@code packageName}; */ public final void notifyHealthCheckPassed(@NonNull String packageName) { - mHandler.post(() -> { - if (mCallback != null) { - Objects.requireNonNull(packageName, - "Package passing explicit health check must be non-null"); - Bundle bundle = new Bundle(); - bundle.putString(EXTRA_HEALTH_CHECK_PASSED_PACKAGE, packageName); - mCallback.sendResult(bundle); - } else { - Log.wtf(TAG, "System missed explicit health check result for " + packageName); - } - }); + if (mCallbackExecutor != null) { + mCallbackExecutor.execute(() -> executeCallback(packageName)); + } else { + mHandler.post(() -> executeCallback(packageName)); + } } /** @@ -296,9 +319,7 @@ public abstract class ExplicitHealthCheckService extends Service { private class ExplicitHealthCheckServiceWrapper extends IExplicitHealthCheckService.Stub { @Override public void setCallback(RemoteCallback callback) throws RemoteException { - mHandler.post(() -> { - mCallback = callback; - }); + mHandler.post(() -> mHealthCheckResultCallback = callback::sendResult); } @Override diff --git a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java index 560e7519de5e..8b8ab587e84a 100644 --- a/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java +++ b/packages/CrashRecovery/services/module/java/com/android/server/PackageWatchdog.java @@ -770,19 +770,19 @@ public class PackageWatchdog { * The minimum value that can be returned by any observer. * It represents that no mitigations were available. */ - public static final int LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT = + public static final int USER_IMPACT_THRESHOLD_NONE = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; /** * The mitigation impact beyond which the user will start noticing the mitigations. */ - public static final int MEDIUM_USER_IMPACT_THRESHOLD = + public static final int USER_IMPACT_THRESHOLD_MEDIUM = PackageHealthObserverImpact.USER_IMPACT_LEVEL_20; /** * The mitigation impact beyond which the user impact is severely high. */ - public static final int HIGH_USER_IMPACT_THRESHOLD = + public static final int USER_IMPACT_THRESHOLD_HIGH = PackageHealthObserverImpact.USER_IMPACT_LEVEL_71; /** @@ -827,11 +827,9 @@ public class PackageWatchdog { public interface PackageHealthObserver { /** * Called when health check fails for the {@code versionedPackage}. - * - * Note: if the returned user impact is higher than - * {@link #DEFAULT_HIGH_USER_IMPACT_THRESHOLD}, then - * {@link #onExecuteHealthCheckMitigation} would be called only in severe device conditions - * like boot-loop or network failure. + * Note: if the returned user impact is higher than {@link #USER_IMPACT_THRESHOLD_HIGH}, + * then {@link #onExecuteHealthCheckMitigation} would be called only in severe device + * conditions like boot-loop or network failure. * * @param versionedPackage the package that is failing. This may be null if a native * service is crashing. @@ -839,9 +837,9 @@ public class PackageWatchdog { * @param mitigationCount the number of times mitigation has been called for this package * (including this time). * - * - * @return any value greater than {@link #LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT} to express - * the impact of mitigation on the user in {@link #onExecuteHealthCheckMitigation} + * @return any value greater than {@link #USER_IMPACT_THRESHOLD_NONE} to express + * the impact of mitigation on the user in {@link #onExecuteHealthCheckMitigation}. + * Returning {@link #USER_IMPACT_THRESHOLD_NONE} would indicate no mitigations available. */ @PackageHealthObserverImpact int onHealthCheckFailed( @Nullable VersionedPackage versionedPackage, @@ -871,8 +869,9 @@ public class PackageWatchdog { * @param mitigationCount the number of times mitigation has been attempted for this * boot loop (including this time). * - * @return any value greater than {@link #LEAST_PACKAGE_HEALTH_OBSERVER_IMPACT} to express - * the impact of mitigation on the user in {@link #onExecuteBootLoopMitigation} + * @return any value greater than {@link #USER_IMPACT_THRESHOLD_NONE} to express + * the impact of mitigation on the user in {@link #onExecuteBootLoopMitigation}. + * Returning {@link #USER_IMPACT_THRESHOLD_NONE} would indicate no mitigations available. */ default @PackageHealthObserverImpact int onBootLoop(int mitigationCount) { return PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; diff --git a/packages/CredentialManager/wear/res/values-hi/strings.xml b/packages/CredentialManager/wear/res/values-hi/strings.xml index a061453e72a4..405d3f8bce18 100644 --- a/packages/CredentialManager/wear/res/values-hi/strings.xml +++ b/packages/CredentialManager/wear/res/values-hi/strings.xml @@ -22,8 +22,8 @@ <string name="use_password_title" msgid="4655101984031246476">"क्या आपको पासवर्ड का इस्तेमाल करना है?"</string> <string name="dialog_dismiss_button" msgid="989567669882005067">"खारिज करें"</string> <string name="dialog_continue_button" msgid="8630290044077052145">"जारी रखें"</string> - <string name="dialog_sign_in_options_button" msgid="448002958902615054">"साइन इन करने के विकल्प"</string> - <string name="sign_in_options_title" msgid="6720572645638986680">"साइन इन करने के विकल्प"</string> + <string name="dialog_sign_in_options_button" msgid="448002958902615054">"साइन-इन करने के विकल्प"</string> + <string name="sign_in_options_title" msgid="6720572645638986680">"साइन-इन करने के विकल्प"</string> <string name="provider_list_title" msgid="6803918216129492212">"साइन-इन क्रेडेंशियल मैनेज करें"</string> <string name="choose_sign_in_title" msgid="3616025924746872202">"साइन इन करने का कोई तरीका चुनें"</string> <string name="choose_passkey_title" msgid="8459270617632817465">"कोई पासकी चुनें"</string> diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index ae04ca158e01..ac436ad5d61a 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -737,7 +737,7 @@ <string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Verander uitvoer"</string> <string name="back_navigation_animation" msgid="8105467568421689484">"Voorspellingteruggebaaranimasies"</string> <string name="back_navigation_animation_summary" msgid="741292224121599456">"Aktiveer stelselanimasies vir voorspellingteruggebaar."</string> - <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Hierdie instelling aktiveer stelselanimasies vir voorspellinggebaaranimasie. Dit vereis dat enableOnBackInvokedCallback per program op waar gestel word in die manifeslêer."</string> + <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Hierdie instelling aktiveer stelselanimasies vir voorspellinggebaaranimasie. Dit vereis dat enableOnBackInvokedCallback per app op waar gestel word in die manifeslêer."</string> <string name="font_scale_percentage" msgid="2624057443622817886">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="not_specified" msgid="5423502443185110328">"Nie gespesifiseer nie"</string> <string name="neuter" msgid="2075249330106127310">"Neutrum"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 690add8f0b1c..a85d0cc02216 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -638,7 +638,7 @@ <string name="user_setup_dialog_title" msgid="8037342066381939995">"ಈಗ ಬಳಕೆದಾರರನ್ನು ಸೆಟ್ ಮಾಡಬೇಕೆ?"</string> <string name="user_setup_dialog_message" msgid="269931619868102841">"ಸಾಧನವನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು ಮತ್ತು ಅದರ ಸ್ಥಳವನ್ನು ಹೊಂದಿಸಲು ವ್ಯಕ್ತಿಯು ಲಭ್ಯವಿದ್ದಾರೆಯೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string> <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"ಇದೀಗ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಹೊಂದಿಸುವುದೇ?"</string> - <string name="user_setup_button_setup_now" msgid="1708269547187760639">"ಇದೀಗ ಹೊಂದಿಸಿ"</string> + <string name="user_setup_button_setup_now" msgid="1708269547187760639">"ಇದೀಗ ಸೆಟ್ ಮಾಡಿ"</string> <string name="user_setup_button_setup_later" msgid="8712980133555493516">"ಈಗಲೇ ಬೇಡ"</string> <string name="user_add_user_type_title" msgid="551279664052914497">"ಸೇರಿಸಿ"</string> <string name="user_new_user_name" msgid="60979820612818840">"ಹೊಸ ಬಳಕೆದಾರರು"</string> @@ -646,7 +646,7 @@ <string name="user_info_settings_title" msgid="6351390762733279907">"ಬಳಕೆದಾರರ ಮಾಹಿತಿ"</string> <string name="profile_info_settings_title" msgid="105699672534365099">"ಪ್ರೊಫೈಲ್ ಮಾಹಿತಿ"</string> <string name="user_need_lock_message" msgid="4311424336209509301">"ನೀವು ನಿರ್ಬಂಧಿತ ಪ್ರೊಫೈಲ್ ಅನ್ನು ರಚಿಸಬಹುದಾದರ ಮೊದಲು, ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ವೈಯಕ್ತಿಕ ಡೇಟಾವನ್ನು ರಕ್ಷಿಸಲು ನೀವು ಪರದೆಯ ಲಾಕ್ ಹೊಂದಿಸುವ ಅಗತ್ಯವಿದೆ."</string> - <string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಹೊಂದಿಸಿ"</string> + <string name="user_set_lock_button" msgid="1427128184982594856">"ಲಾಕ್ ಸೆಟ್ ಮಾಡಿ"</string> <string name="user_switch_to_user" msgid="6975428297154968543">"<xliff:g id="USER_NAME">%s</xliff:g>ಗೆ ಬದಲಿಸಿ"</string> <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string> <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"ಹೊಸ ಅತಿಥಿಯನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 4eb0567c67d9..b58983ff1ce8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -17,6 +17,7 @@ package com.android.settingslib.bluetooth; import static com.android.settingslib.flags.Flags.enableSetPreferredTransportForLeAudioDevice; +import static com.android.settingslib.flags.Flags.ignoreA2dpDisconnectionForAndroidAuto; import android.annotation.CallbackExecutor; import android.annotation.StringRes; @@ -82,6 +83,8 @@ import java.util.stream.Stream; */ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> { private static final String TAG = "CachedBluetoothDevice"; + private static final ParcelUuid ANDROID_AUTO_UUID = + ParcelUuid.fromString("4de17a00-52cb-11e6-bdf4-0800200c9a66"); // See mConnectAttempted private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000; @@ -260,18 +263,26 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (mHandler.hasMessages(profile.getProfileId())) { mHandler.removeMessages(profile.getProfileId()); if (profile.getConnectionPolicy(mDevice) > - BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { - /* - * If we received state DISCONNECTED and previous state was - * CONNECTING and connection policy is FORBIDDEN or UNKNOWN - * then it's not really a failure to connect. - * - * Connection profile is considered as failed when connection - * policy indicates that profile should be connected - * but it got disconnected. - */ - Log.w(TAG, "onProfileStateChanged(): Failed to connect profile"); - setProfileConnectedStatus(profile.getProfileId(), true); + BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) { + if (ignoreA2dpDisconnectionForAndroidAuto() + && profile instanceof A2dpProfile && isAndroidAuto()) { + Log.w(TAG, + "onProfileStateChanged(): Skip setting A2DP " + + "connection fail for Android Auto"); + } else { + /* + * If we received state DISCONNECTED and previous state was + * CONNECTING and connection policy is FORBIDDEN or UNKNOWN + * then it's not really a failure to connect. + * + * Connection profile is considered as failed when connection + * policy indicates that profile should be connected + * but it got disconnected. + */ + Log.w(TAG, + "onProfileStateChanged(): Failed to connect profile"); + setProfileConnectedStatus(profile.getProfileId(), true); + } } } break; @@ -2031,4 +2042,16 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> void setLocalBluetoothManager(LocalBluetoothManager bluetoothManager) { mBluetoothManager = bluetoothManager; } + + private boolean isAndroidAuto() { + try { + ParcelUuid[] uuids = mDevice.getUuids(); + if (ArrayUtils.contains(uuids, ANDROID_AUTO_UUID)) { + return true; + } + } catch (RuntimeException e) { + Log.w(TAG, "Fail to check isAndroidAuto for " + this); + } + return false; + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java index 76aa5bf3334c..478a5d198239 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InputRouteManager.java @@ -80,8 +80,14 @@ public final class InputRouteManager { // behavior. @AudioDeviceType int deviceTypeToActivate = mSelectedInputDeviceType; for (AudioDeviceInfo info : addedDevices) { - if (InputMediaDevice.isSupportedInputDevice(info.getType())) { - deviceTypeToActivate = info.getType(); + @AudioDeviceType int type = info.getType(); + // Since onAudioDevicesAdded is called not only when new device is hot + // plugged, but also when the switcher dialog is opened, make sure to check + // against existing device list and only activate if the device does not + // exist previously. + if (InputMediaDevice.isSupportedInputDevice(type) + && findDeviceByType(type) == null) { + deviceTypeToActivate = type; } } @@ -140,16 +146,22 @@ public final class InputRouteManager { } // TODO(b/355684672): handle edge case where there are two devices with the same type. Only - // using a single mSelectedInputDeviceType might not be enough to recognize the correct device. - public @Nullable MediaDevice getSelectedInputDevice() { + // using a single type might not be enough to recognize the correct device. + @Nullable + private MediaDevice findDeviceByType(@AudioDeviceType int type) { for (MediaDevice device : mInputMediaDevices) { - if (((InputMediaDevice) device).getAudioDeviceInfoType() == mSelectedInputDeviceType) { + if (((InputMediaDevice) device).getAudioDeviceInfoType() == type) { return device; } } return null; } + @Nullable + public MediaDevice getSelectedInputDevice() { + return findDeviceByType(mSelectedInputDeviceType); + } + private void applyDefaultSelectedTypeToAllPresets() { mSelectedInputDeviceType = retrieveDefaultSelectedDeviceType(); AudioDeviceAttributes deviceAttributes = diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java index d808a25ebc04..9c34946f0c1b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputRouteManagerTest.java @@ -361,6 +361,26 @@ public class InputRouteManagerTest { } @Test + public void onAudioDevicesAdded_doNotActivatePreexistingDevice() { + final AudioManager audioManager = mock(AudioManager.class); + InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); + + final AudioDeviceInfo info = mockWiredHeadsetInfo(); + InputMediaDevice device = createInputMediaDeviceFromDeviceInfo(info); + inputRouteManager.mInputMediaDevices.add(device); + + // Trigger onAudioDevicesAdded with a device that already exists in the device list. + AudioDeviceInfo[] devices = {info}; + inputRouteManager.mAudioDeviceCallback.onAudioDevicesAdded(devices); + + // The device should not be activated. + for (@MediaRecorder.Source int preset : PRESETS) { + verify(audioManager, never()) + .setPreferredDeviceForCapturePreset(preset, getWiredHeadsetDeviceAttributes()); + } + } + + @Test public void onAudioDevicesRemoved_shouldApplyDefaultSelectedDeviceToAllPresets() { final AudioManager audioManager = mock(AudioManager.class); InputRouteManager inputRouteManager = new InputRouteManager(mContext, audioManager); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index baf829ab3b14..65f487765c1e 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -740,9 +740,6 @@ <uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" /> <uses-permission android:name="android.permission.DEBUG_VIRTUAL_MACHINE" /> - <!-- Permission required to access bugreport and screenshot files created by wear. --> - <uses-permission android:name="com.google.wear.permission.ACCESS_BUG_REPORT_FILES" /> - <!-- Permission required to run GtsAssistantTestCases --> <uses-permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES" /> @@ -992,6 +989,10 @@ <uses-permission android:name="android.permission.health.READ_SKIN_TEMPERATURE" android:featureFlag="android.permission.flags.replace_body_sensor_permission_enabled"/> + <!-- Permission for TestClassifier tests to get access to classifier by type --> + <uses-permission android:name="android.permission.ACCESS_TEXT_CLASSIFIER_BY_TYPE" + android:featureFlag="android.permission.flags.text_classifier_choice_api_enabled"/> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" diff --git a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ne/strings.xml b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ne/strings.xml index 10e36b872b04..9506a7e381b9 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/res/values-ne/strings.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/res/values-ne/strings.xml @@ -11,7 +11,7 @@ <string name="recent_apps_label" msgid="6583276995616385847">"हालै चलाइएका एप"</string> <string name="lockscreen_label" msgid="648347953557887087">"लक स्क्रिन"</string> <string name="quick_settings_label" msgid="2999117381487601865">"द्रुत सेटिङहरू"</string> - <string name="notifications_label" msgid="6829741046963013567">"सूचनाहरू"</string> + <string name="notifications_label" msgid="6829741046963013567">"नोटिफिकेसनहरू"</string> <string name="screenshot_label" msgid="863978141223970162">"स्क्रिनसट"</string> <string name="screenshot_utterance" msgid="1430760563401895074">"स्क्रिनसट लिनुहोस्"</string> <string name="volume_up_label" msgid="8592766918780362870">"भोल्युम बढाउनुहोस्"</string> 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 558c1eba2c1c..65cd3c79cd16 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt @@ -397,6 +397,10 @@ constructor( ghostedView.visibility = View.VISIBLE ghostedView.invalidate() } + + if (isEphemeral) { + onDispose() + } } companion object { diff --git a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt index 58b883658b03..9fe85b7a7070 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/gesture/NestedDraggable.kt @@ -111,22 +111,24 @@ fun Modifier.nestedDraggable( draggable: NestedDraggable, orientation: Orientation, overscrollEffect: OverscrollEffect? = null, + enabled: Boolean = true, ): Modifier { return this.thenIf(overscrollEffect != null) { Modifier.overscroll(overscrollEffect) } - .then(NestedDraggableElement(draggable, orientation, overscrollEffect)) + .then(NestedDraggableElement(draggable, orientation, overscrollEffect, enabled)) } private data class NestedDraggableElement( private val draggable: NestedDraggable, private val orientation: Orientation, private val overscrollEffect: OverscrollEffect?, + private val enabled: Boolean, ) : ModifierNodeElement<NestedDraggableNode>() { override fun create(): NestedDraggableNode { - return NestedDraggableNode(draggable, orientation, overscrollEffect) + return NestedDraggableNode(draggable, orientation, overscrollEffect, enabled) } override fun update(node: NestedDraggableNode) { - node.update(draggable, orientation, overscrollEffect) + node.update(draggable, orientation, overscrollEffect, enabled) } } @@ -134,6 +136,7 @@ private class NestedDraggableNode( private var draggable: NestedDraggable, override var orientation: Orientation, private var overscrollEffect: OverscrollEffect?, + private var enabled: Boolean, ) : DelegatingNode(), PointerInputModifierNode, @@ -179,14 +182,22 @@ private class NestedDraggableNode( draggable: NestedDraggable, orientation: Orientation, overscrollEffect: OverscrollEffect?, + enabled: Boolean, ) { this.draggable = draggable this.orientation = orientation this.overscrollEffect = overscrollEffect + this.enabled = enabled trackDownPositionDelegate?.resetPointerInputHandler() detectDragsDelegate?.resetPointerInputHandler() nestedScrollController?.ensureOnDragStoppedIsCalled() + + if (!enabled && trackDownPositionDelegate != null) { + check(detectDragsDelegate != null) + trackDownPositionDelegate = null + detectDragsDelegate = null + } } override fun onPointerEvent( @@ -194,6 +205,8 @@ private class NestedDraggableNode( pass: PointerEventPass, bounds: IntSize, ) { + if (!enabled) return + if (trackDownPositionDelegate == null) { check(detectDragsDelegate == null) trackDownPositionDelegate = SuspendingPointerInputModifierNode { trackDownPosition() } diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt index f8561b8379f9..fd3902fa7dc8 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/gesture/NestedDraggableTest.kt @@ -344,6 +344,45 @@ class NestedDraggableTest(override val orientation: Orientation) : OrientationAw assertThat(draggable.onDragStoppedCalled).isTrue() } + @Test + fun enabled() { + val draggable = TestDraggable() + var enabled by mutableStateOf(false) + val touchSlop = + rule.setContentWithTouchSlop { + Box( + Modifier.fillMaxSize() + .nestedDraggable(draggable, orientation, enabled = enabled) + ) + } + + assertThat(draggable.onDragStartedCalled).isFalse() + + rule.onRoot().performTouchInput { + down(center) + moveBy(touchSlop.toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isFalse() + assertThat(draggable.onDragStoppedCalled).isFalse() + + enabled = true + rule.onRoot().performTouchInput { + // Release previously up finger. + up() + + down(center) + moveBy(touchSlop.toOffset()) + } + + assertThat(draggable.onDragStartedCalled).isTrue() + assertThat(draggable.onDragStoppedCalled).isFalse() + + enabled = false + rule.waitForIdle() + assertThat(draggable.onDragStoppedCalled).isTrue() + } + private fun ComposeContentTestRule.setContentWithTouchSlop( content: @Composable () -> Unit ): Float { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt index 3926b326dacd..a17a1d46554f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -23,12 +23,17 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntRect +import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import com.android.compose.animation.scene.SceneScope import com.android.systemui.communal.smartspace.SmartspaceInteractionHandler import com.android.systemui.communal.ui.compose.section.AmbientStatusBarSection import com.android.systemui.communal.ui.compose.section.CommunalPopupSection +import com.android.systemui.communal.ui.compose.section.CommunalToDreamButtonSection import com.android.systemui.communal.ui.view.layout.sections.CommunalAppWidgetSection import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines @@ -49,6 +54,7 @@ constructor( private val ambientStatusBarSection: AmbientStatusBarSection, private val communalPopupSection: CommunalPopupSection, private val widgetSection: CommunalAppWidgetSection, + private val communalToDreamButtonSection: CommunalToDreamButtonSection, ) { @Composable @@ -82,11 +88,13 @@ constructor( Modifier.element(Communal.Elements.IndicationArea).fillMaxWidth() ) } + with(communalToDreamButtonSection) { Button() } }, ) { measurables, constraints -> val communalGridMeasurable = measurables[0] val lockIconMeasurable = measurables[1] val bottomAreaMeasurable = measurables[2] + val screensaverButtonMeasurable: Measurable? = measurables.getOrNull(3) val noMinConstraints = constraints.copy(minWidth = 0, minHeight = 0) @@ -101,6 +109,15 @@ constructor( val bottomAreaPlaceable = bottomAreaMeasurable.measure(noMinConstraints) + val screensaverButtonSizeInt = screensaverButtonSize.roundToPx() + val screensaverButtonPlaceable = + screensaverButtonMeasurable?.measure( + Constraints.fixed( + width = screensaverButtonSizeInt, + height = screensaverButtonSizeInt, + ) + ) + val communalGridPlaceable = communalGridMeasurable.measure( noMinConstraints.copy(maxHeight = lockIconBounds.top) @@ -109,12 +126,22 @@ constructor( layout(constraints.maxWidth, constraints.maxHeight) { communalGridPlaceable.place(x = 0, y = 0) lockIconPlaceable.place(x = lockIconBounds.left, y = lockIconBounds.top) - bottomAreaPlaceable.place( - x = 0, - y = constraints.maxHeight - bottomAreaPlaceable.height, + + val bottomAreaTop = constraints.maxHeight - bottomAreaPlaceable.height + bottomAreaPlaceable.place(x = 0, y = bottomAreaTop) + screensaverButtonPlaceable?.place( + x = + constraints.maxWidth - + screensaverButtonSizeInt - + Dimensions.ItemSpacing.roundToPx(), + y = lockIconBounds.top, ) } } } } + + companion object { + val screensaverButtonSize: Dp = 64.dp + } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index 573e5ca5e2d5..a55b6d720dd6 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -187,6 +187,7 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.ui.viewmodel.ResizeInfo import com.android.systemui.communal.ui.viewmodel.ResizeableItemFrameViewModel import com.android.systemui.communal.util.DensityUtils.Companion.adjustedDp +import com.android.systemui.communal.util.ResizeUtils.resizeOngoingItems import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView import com.android.systemui.communal.widgets.WidgetConfigurator import com.android.systemui.lifecycle.rememberViewModel @@ -217,6 +218,7 @@ fun CommunalHub( var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) } var toolbarSize: IntSize? by remember { mutableStateOf(null) } var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) } + var contentOffset: Offset by remember { mutableStateOf(Offset.Zero) } val gridState = rememberLazyGridState(viewModel.savedFirstScrollIndex, viewModel.savedFirstScrollOffset) @@ -239,9 +241,7 @@ fun CommunalHub( initialValue = !viewModel.isEditMode ) - val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize) - val contentOffset = beforeContentPadding(contentPadding).toOffset() - + val minContentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize) ObserveScrollEffect(gridState, viewModel) val context = LocalContext.current @@ -367,7 +367,7 @@ fun CommunalHub( ) { AccessibilityContainer(viewModel) { if (!viewModel.isEditMode && isEmptyState) { - EmptyStateCta(contentPadding = contentPadding, viewModel = viewModel) + EmptyStateCta(contentPadding = minContentPadding, viewModel = viewModel) } else { val slideOffsetInPx = with(LocalDensity.current) { Dimensions.SlideOffsetY.toPx().toInt() } @@ -396,10 +396,11 @@ fun CommunalHub( CommunalHubLazyGrid( communalContent = communalContent, viewModel = viewModel, - contentPadding = contentPadding, + minContentPadding = minContentPadding, contentOffset = contentOffset, screenWidth = screenWidth, setGridCoordinates = { gridCoordinates = it }, + setContentOffset = { contentOffset = it }, updateDragPositionForRemove = { boundingBox -> val gridOffset = gridCoordinates?.positionInWindow() val removeButtonCenter = @@ -741,8 +742,9 @@ fun calculateWidgetSize( @Composable private fun HorizontalGridWrapper( - contentPadding: PaddingValues, + minContentPadding: PaddingValues, gridState: LazyGridState, + setContentOffset: (offset: Offset) -> Unit, modifier: Modifier = Modifier, content: LazyGridScope.(sizeInfo: SizeInfo?) -> Unit, ) { @@ -751,17 +753,26 @@ private fun HorizontalGridWrapper( cellAspectRatio = 1.5f, modifier = modifier, state = gridState, - minContentPadding = contentPadding, + minContentPadding = minContentPadding, minHorizontalArrangement = Dimensions.ItemSpacing, minVerticalArrangement = Dimensions.ItemSpacing, + setContentOffset = setContentOffset, content = content, ) } else { + val layoutDirection = LocalLayoutDirection.current + val density = LocalDensity.current + + val minStartPadding = minContentPadding.calculateStartPadding(layoutDirection) + val minTopPadding = minContentPadding.calculateTopPadding() + + with(density) { setContentOffset(Offset(minStartPadding.toPx(), minTopPadding.toPx())) } + LazyHorizontalGrid( modifier = modifier, state = gridState, rows = GridCells.Fixed(CommunalContentSize.FixedSize.FULL.span), - contentPadding = contentPadding, + contentPadding = minContentPadding, horizontalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing), verticalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing), ) { @@ -775,13 +786,14 @@ private fun HorizontalGridWrapper( private fun BoxScope.CommunalHubLazyGrid( communalContent: List<CommunalContentModel>, viewModel: BaseCommunalViewModel, - contentPadding: PaddingValues, + minContentPadding: PaddingValues, selectedKey: State<String?>, screenWidth: Int, contentOffset: Offset, gridState: LazyGridState, contentListState: ContentListState, setGridCoordinates: (coordinates: LayoutCoordinates) -> Unit, + setContentOffset: (offset: Offset) -> Unit, updateDragPositionForRemove: (boundingBox: IntRect) -> Boolean, widgetConfigurator: WidgetConfigurator?, interactionHandler: RemoteViews.InteractionHandler?, @@ -832,10 +844,19 @@ private fun BoxScope.CommunalHubLazyGrid( HorizontalGridWrapper( modifier = gridModifier, gridState = gridState, - contentPadding = contentPadding, + minContentPadding = minContentPadding, + setContentOffset = setContentOffset, ) { sizeInfo -> + /** Override spans based on the responsive grid size */ + val finalizedList = + if (sizeInfo != null) { + resizeOngoingItems(list, sizeInfo.gridSize.height) + } else { + list + } + itemsIndexed( - items = list, + items = finalizedList, key = { _, item -> item.key }, contentType = { _, item -> item.key }, span = { _, item -> GridItemSpan(item.getSpanOrMax(sizeInfo?.gridSize?.height)) }, @@ -883,7 +904,7 @@ private fun BoxScope.CommunalHubLazyGrid( key = item.key, currentSpan = GridItemSpan(currentItemSpan), gridState = gridState, - gridContentPadding = contentPadding, + gridContentPadding = sizeInfo?.contentPadding ?: minContentPadding, verticalArrangement = Arrangement.spacedBy( sizeInfo?.verticalArrangement ?: Dimensions.ItemSpacing @@ -1193,6 +1214,7 @@ private fun CommunalContent( is CommunalContentModel.Smartspace -> SmartspaceContent(interactionHandler, model, modifier) is CommunalContentModel.Tutorial -> TutorialContent(modifier) is CommunalContentModel.Umo -> Umo(viewModel, sceneScope, modifier) + is CommunalContentModel.Spacer -> Box(Modifier.fillMaxSize()) } } @@ -1723,24 +1745,22 @@ private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): Padd val windowMetrics = WindowMetricsCalculator.getOrCreate().computeCurrentWindowMetrics(context) val screenHeight = with(density) { windowMetrics.bounds.height().toDp() } val toolbarHeight = with(density) { Dimensions.ToolbarPaddingTop + toolbarSize.height.toDp() } - val verticalPadding = - ((screenHeight - toolbarHeight - hubDimensions.GridHeight + hubDimensions.GridTopSpacing) / - 2) - .coerceAtLeast(Dimensions.Spacing) - return PaddingValues( - start = Dimensions.ToolbarPaddingHorizontal, - end = Dimensions.ToolbarPaddingHorizontal, - top = verticalPadding + toolbarHeight, - bottom = verticalPadding, - ) -} - -@Composable -private fun beforeContentPadding(paddingValues: PaddingValues): ContentPaddingInPx { - return with(LocalDensity.current) { - ContentPaddingInPx( - start = paddingValues.calculateStartPadding(LocalLayoutDirection.current).toPx(), - top = paddingValues.calculateTopPadding().toPx(), + return if (communalResponsiveGrid()) { + PaddingValues( + start = Dimensions.ToolbarPaddingHorizontal, + end = Dimensions.ToolbarPaddingHorizontal, + top = hubDimensions.GridTopSpacing, + ) + } else { + val verticalPadding = + ((screenHeight - toolbarHeight - hubDimensions.GridHeight + + hubDimensions.GridTopSpacing) / 2) + .coerceAtLeast(Dimensions.Spacing) + PaddingValues( + start = Dimensions.ToolbarPaddingHorizontal, + end = Dimensions.ToolbarPaddingHorizontal, + top = verticalPadding + toolbarHeight, + bottom = verticalPadding, ) } } @@ -1760,10 +1780,6 @@ private fun firstIndexAtOffset(gridState: LazyGridState, offset: Offset): Int? = private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? = if (index in list.indices && list[index].isWidgetContent()) list[index].key else null -data class ContentPaddingInPx(val start: Float, val top: Float) { - fun toOffset(): Offset = Offset(start, top) -} - class Dimensions(val context: Context, val config: Configuration) { val GridTopSpacing: Dp get() { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt index 7a500805809d..ef5e90bd7aad 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt @@ -94,7 +94,7 @@ internal constructor( private val scope: CoroutineScope, private val updateDragPositionForRemove: (draggingBoundingBox: IntRect) -> Boolean, ) { - var draggingItemKey by mutableStateOf<String?>(null) + var draggingItemKey by mutableStateOf<Any?>(null) private set var isDraggingToRemove by mutableStateOf(false) @@ -138,7 +138,7 @@ internal constructor( // before content padding from the initial pointer position .firstItemAtOffset(normalizedOffset - contentOffset) ?.apply { - draggingItemKey = key as String + draggingItemKey = key draggingItemInitialOffset = this.offset.toOffset() return true } @@ -284,9 +284,7 @@ fun Modifier.dragContainer( contentOffset, ) ) { - // draggingItemKey is guaranteed to be non-null here because it is set in - // onDragStart() - viewModel.onReorderWidgetStart(dragDropState.draggingItemKey!!) + viewModel.onReorderWidgetStart() } }, onDragEnd = { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt index 3642127d0823..21b34748a364 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ResponsiveLazyHorizontalGrid.kt @@ -35,7 +35,9 @@ import androidx.compose.foundation.rememberOverscrollEffect import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize @@ -54,6 +56,7 @@ fun ResponsiveLazyHorizontalGrid( cellAspectRatio: Float, modifier: Modifier = Modifier, state: LazyGridState = rememberLazyGridState(), + setContentOffset: (offset: Offset) -> Unit = {}, minContentPadding: PaddingValues = PaddingValues(0.dp), minHorizontalArrangement: Dp = 0.dp, minVerticalArrangement: Dp = 0.dp, @@ -70,6 +73,7 @@ fun ResponsiveLazyHorizontalGrid( BoxWithConstraints(modifier) { val gridSize = rememberGridSize(maxWidth = maxWidth, maxHeight = maxHeight) val layoutDirection = LocalLayoutDirection.current + val density = LocalDensity.current val minStartPadding = minContentPadding.calculateStartPadding(layoutDirection) val minEndPadding = minContentPadding.calculateEndPadding(layoutDirection) @@ -124,14 +128,19 @@ fun ResponsiveLazyHorizontalGrid( val extraWidth = maxWidth - usedWidth val extraHeight = maxHeight - usedHeight + val finalStartPadding = minStartPadding + extraWidth / 2 + val finalTopPadding = minTopPadding + extraHeight / 2 + val finalContentPadding = PaddingValues( - start = minStartPadding + extraWidth / 2, + start = finalStartPadding, end = minEndPadding + extraWidth / 2, - top = minTopPadding + extraHeight / 2, + top = finalTopPadding, bottom = minBottomPadding + extraHeight / 2, ) + with(density) { setContentOffset(Offset(finalStartPadding.toPx(), finalTopPadding.toPx())) } + LazyHorizontalGrid( rows = GridCells.Fixed(gridSize.height), modifier = Modifier.fillMaxSize(), @@ -179,12 +188,13 @@ private fun calculateClosestSize(maxWidth: Dp, maxHeight: Dp, aspectRatio: Float * @property verticalArrangement The space between rows in the grid. * @property gridSize The size of the grid, in cell units. * @property availableHeight The maximum height an item in the grid may occupy. + * @property contentPadding The padding around the content of the grid. */ data class SizeInfo( val cellSize: DpSize, val verticalArrangement: Dp, val gridSize: IntSize, - private val contentPadding: PaddingValues, + val contentPadding: PaddingValues, private val maxHeight: Dp, ) { val availableHeight: Dp diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.kt new file mode 100644 index 000000000000..9421596f7116 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/section/CommunalToDreamButtonSection.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.communal.ui.compose.section + +import androidx.compose.material3.IconButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.android.compose.PlatformIconButton +import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor +import com.android.systemui.communal.ui.viewmodel.CommunalToDreamButtonViewModel +import com.android.systemui.lifecycle.rememberViewModel +import com.android.systemui.res.R +import javax.inject.Inject + +class CommunalToDreamButtonSection +@Inject +constructor( + private val communalSettingsInteractor: CommunalSettingsInteractor, + private val viewModelFactory: CommunalToDreamButtonViewModel.Factory, +) { + @Composable + fun Button() { + if (!communalSettingsInteractor.isV2FlagEnabled()) { + return + } + + val viewModel = + rememberViewModel("CommunalToDreamButtonSection") { viewModelFactory.create() } + val shouldShowDreamButtonOnHub by + viewModel.shouldShowDreamButtonOnHub.collectAsStateWithLifecycle(false) + + if (!shouldShowDreamButtonOnHub) { + return + } + + PlatformIconButton( + onClick = { viewModel.onShowDreamButtonTap() }, + iconResource = R.drawable.ic_screensaver_auto, + contentDescription = + stringResource(R.string.accessibility_glanceable_hub_to_dream_button), + colors = + IconButtonDefaults.filledIconButtonColors( + contentColor = MaterialTheme.colorScheme.onPrimaryContainer, + containerColor = MaterialTheme.colorScheme.primaryContainer, + ), + ) + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt index da78eed2612b..1cee4d67df3b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt @@ -77,7 +77,7 @@ constructor( resources.getDimensionPixelSize( R.dimen.keyguard_status_view_bottom_margin ) - } + }, ) ) { if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) { @@ -87,6 +87,7 @@ constructor( val paddingBelowClockStart = dimensionResource(R.dimen.below_clock_padding_start) val paddingBelowClockEnd = dimensionResource(R.dimen.below_clock_padding_end) + val paddingCardHorizontal = paddingBelowClockEnd if (keyguardSmartspaceViewModel.isDateWeatherDecoupled) { Row( @@ -96,16 +97,14 @@ constructor( // All items will be constrained to be as tall as the shortest // item. .height(IntrinsicSize.Min) - .padding( - start = paddingBelowClockStart, - ), + .padding(start = paddingBelowClockStart), ) { Date( modifier = Modifier.burnInAware( viewModel = aodBurnInViewModel, params = burnInParams, - ), + ) ) Spacer(modifier = Modifier.width(4.dp)) Weather( @@ -113,7 +112,7 @@ constructor( Modifier.burnInAware( viewModel = aodBurnInViewModel, params = burnInParams, - ), + ) ) } } @@ -121,14 +120,8 @@ constructor( Card( modifier = Modifier.fillMaxWidth() - .padding( - start = paddingBelowClockStart, - end = paddingBelowClockEnd, - ) - .burnInAware( - viewModel = aodBurnInViewModel, - params = burnInParams, - ), + .padding(start = paddingCardHorizontal, end = paddingCardHorizontal) + .burnInAware(viewModel = aodBurnInViewModel, params = burnInParams) ) } } @@ -136,9 +129,7 @@ constructor( } @Composable - private fun Card( - modifier: Modifier = Modifier, - ) { + private fun Card(modifier: Modifier = Modifier) { AndroidView( factory = { context -> FrameLayout(context).apply { @@ -161,9 +152,7 @@ constructor( } @Composable - private fun Weather( - modifier: Modifier = Modifier, - ) { + private fun Weather(modifier: Modifier = Modifier) { val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsStateWithLifecycle() if (!isVisible) { return @@ -188,9 +177,7 @@ constructor( } @Composable - private fun Date( - modifier: Modifier = Modifier, - ) { + private fun Date(modifier: Modifier = Modifier) { val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsStateWithLifecycle() if (!isVisible) { return 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 f1da01fef72c..4410e157b526 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 @@ -771,7 +771,7 @@ class ElementTest { private fun expectedOffset(currentOffset: Dp, density: Density): Dp { return with(density) { - OffsetOverscrollEffect.computeOffset(this, currentOffset.toPx()).toDp() + OffsetOverscrollEffect.computeOffset(density, currentOffset.toPx()).toDp() } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt index d267cc5c237f..da8fe3094448 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/effect/OffsetOverscrollEffectTest.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 +import kotlin.properties.Delegates import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -44,165 +45,131 @@ import org.junit.runner.RunWith class OffsetOverscrollEffectTest { @get:Rule val rule = createComposeRule() - private fun expectedOffset(currentOffset: Dp, density: Density): Dp { - return with(density) { - OffsetOverscrollEffect.computeOffset(this, currentOffset.toPx()).toDp() + private val BOX_TAG = "box" + + private data class LayoutInfo(val layoutSize: Dp, val touchSlop: Float, val density: Density) { + fun expectedOffset(currentOffset: Dp): Dp { + return with(density) { + OffsetOverscrollEffect.computeOffset(this, currentOffset.toPx()).toDp() + } } } - @Test - fun applyVerticalOffset_duringVerticalOverscroll() { + private fun setupOverscrollableBox( + scrollableOrientation: Orientation, + overscrollEffectOrientation: Orientation = scrollableOrientation, + ): LayoutInfo { + val layoutSize: Dp = 200.dp + var touchSlop: Float by Delegates.notNull() // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. - var touchSlop = 0f lateinit var density: Density - val layoutSize = 200.dp - rule.setContent { density = LocalDensity.current touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) + val overscrollEffect = rememberOffsetOverscrollEffect(overscrollEffectOrientation) Box( Modifier.overscroll(overscrollEffect) // A scrollable that does not consume the scroll gesture. .scrollable( state = rememberScrollableState { 0f }, - orientation = Orientation.Vertical, + orientation = scrollableOrientation, overscrollEffect = overscrollEffect, ) .size(layoutSize) - .testTag("box") + .testTag(BOX_TAG) ) } + return LayoutInfo(layoutSize, touchSlop, density) + } - val onBox = rule.onNodeWithTag("box") + @Test + fun applyVerticalOffset_duringVerticalOverscroll() { + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) - onBox.assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) rule.onRoot().performTouchInput { down(center) - moveBy(Offset(0f, touchSlop + layoutSize.toPx()), delayMillis = 1_000) + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(expectedOffset(layoutSize, density)) + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) } @Test fun applyNoOffset_duringHorizontalOverscroll() { - // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is - // detected as a drag event. - var touchSlop = 0f - val layoutSize = 200.dp - - rule.setContent { - touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) - - Box( - Modifier.overscroll(overscrollEffect) - // A scrollable that does not consume the scroll gesture. - .scrollable( - state = rememberScrollableState { 0f }, - orientation = Orientation.Horizontal, - overscrollEffect = overscrollEffect, - ) - .size(layoutSize) - .testTag("box") + val info = + setupOverscrollableBox( + scrollableOrientation = Orientation.Vertical, + overscrollEffectOrientation = Orientation.Horizontal, ) - } - val onBox = rule.onNodeWithTag("box") - - onBox.assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) rule.onRoot().performTouchInput { down(center) - moveBy(Offset(touchSlop + layoutSize.toPx(), 0f), delayMillis = 1_000) + moveBy(Offset(info.touchSlop + info.layoutSize.toPx(), 0f), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) } @Test fun backToZero_afterOverscroll() { - // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is - // detected as a drag event. - var touchSlop = 0f - lateinit var density: Density - val layoutSize = 200.dp - - rule.setContent { - density = LocalDensity.current - touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) - - Box( - Modifier.overscroll(overscrollEffect) - // A scrollable that does not consume the scroll gesture. - .scrollable( - state = rememberScrollableState { 0f }, - orientation = Orientation.Vertical, - overscrollEffect = overscrollEffect, - ) - .size(layoutSize) - .testTag("box") - ) - } - - val onBox = rule.onNodeWithTag("box") + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) rule.onRoot().performTouchInput { down(center) - moveBy(Offset(0f, touchSlop + layoutSize.toPx()), delayMillis = 1_000) + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(expectedOffset(layoutSize, density)) + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) rule.onRoot().performTouchInput { up() } - onBox.assertTopPositionInRootIsEqualTo(0.dp) + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) } @Test fun offsetOverscroll_followTheTouchPointer() { - // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is - // detected as a drag event. - var touchSlop = 0f - lateinit var density: Density - val layoutSize = 200.dp - - rule.setContent { - density = LocalDensity.current - touchSlop = LocalViewConfiguration.current.touchSlop - val overscrollEffect = rememberOffsetOverscrollEffect(Orientation.Vertical) - - Box( - Modifier.overscroll(overscrollEffect) - // A scrollable that does not consume the scroll gesture. - .scrollable( - state = rememberScrollableState { 0f }, - orientation = Orientation.Vertical, - overscrollEffect = overscrollEffect, - ) - .size(layoutSize) - .testTag("box") - ) - } - - val onBox = rule.onNodeWithTag("box") + val info = setupOverscrollableBox(scrollableOrientation = Orientation.Vertical) + // First gesture, drag down. rule.onRoot().performTouchInput { down(center) // A full screen scroll. - moveBy(Offset(0f, touchSlop + layoutSize.toPx()), delayMillis = 1_000) + moveBy(Offset(0f, info.touchSlop + info.layoutSize.toPx()), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(expectedOffset(layoutSize, density)) + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize)) rule.onRoot().performTouchInput { // Reduced by half. - moveBy(Offset(0f, -layoutSize.toPx() / 2), delayMillis = 1_000) + moveBy(Offset(0f, -info.layoutSize.toPx() / 2), delayMillis = 1_000) + } + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(info.layoutSize / 2)) + + rule.onRoot().performTouchInput { up() } + // Animate back to 0. + rule.onNodeWithTag(BOX_TAG).assertTopPositionInRootIsEqualTo(0.dp) + + // Second gesture, drag up. + rule.onRoot().performTouchInput { + down(center) + // A full screen scroll. + moveBy(Offset(0f, -info.touchSlop - info.layoutSize.toPx()), delayMillis = 1_000) } - onBox.assertTopPositionInRootIsEqualTo(expectedOffset(layoutSize / 2, density)) + rule + .onNodeWithTag(BOX_TAG) + .assertTopPositionInRootIsEqualTo(info.expectedOffset(-info.layoutSize)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt new file mode 100644 index 000000000000..88206850eb60 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelTest.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.communal.ui.viewmodel + +import android.platform.test.annotations.EnableFlags +import android.service.dream.dreamManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2 +import com.android.systemui.SysuiTestCase +import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED +import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runCurrent +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.lifecycle.activateIn +import com.android.systemui.statusbar.policy.batteryController +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 +import org.mockito.Mockito.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.whenever + +@SmallTest +@EnableFlags(FLAG_GLANCEABLE_HUB_V2) +@RunWith(AndroidJUnit4::class) +class CommunalToDreamButtonViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val underTest: CommunalToDreamButtonViewModel by lazy { + kosmos.communalToDreamButtonViewModel + } + + @Before + fun setUp() { + kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true) + underTest.activateIn(testScope) + } + + @Test + fun shouldShowDreamButtonOnHub_trueWhenCanDream() = + with(kosmos) { + runTest { + whenever(dreamManager.canStartDreaming(any())).thenReturn(true) + whenever(batteryController.isPluggedIn()).thenReturn(true) + + val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) + assertThat(shouldShowButton).isTrue() + } + } + + @Test + fun shouldShowDreamButtonOnHub_falseWhenCannotDream() = + with(kosmos) { + runTest { + whenever(dreamManager.canStartDreaming(any())).thenReturn(false) + whenever(batteryController.isPluggedIn()).thenReturn(true) + + val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) + assertThat(shouldShowButton).isFalse() + } + } + + @Test + fun shouldShowDreamButtonOnHub_falseWhenNotPluggedIn() = + with(kosmos) { + runTest { + whenever(dreamManager.canStartDreaming(any())).thenReturn(true) + whenever(batteryController.isPluggedIn()).thenReturn(false) + + val shouldShowButton by collectLastValue(underTest.shouldShowDreamButtonOnHub) + assertThat(shouldShowButton).isFalse() + } + } + + @Test + fun onShowDreamButtonTap_startsDream() = + with(kosmos) { + runTest { + underTest.onShowDreamButtonTap() + runCurrent() + + verify(dreamManager).startDream() + } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/util/ResizeUtilsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/util/ResizeUtilsTest.kt new file mode 100644 index 000000000000..b0f48038877e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/util/ResizeUtilsTest.kt @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.util + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.domain.model.CommunalContentModel +import com.android.systemui.communal.shared.model.CommunalContentSize +import com.android.systemui.communal.util.ResizeUtils.resizeOngoingItems +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock + +@SmallTest +@RunWith(AndroidJUnit4::class) +class ResizeUtilsTest : SysuiTestCase() { + private val mockWidget = + mock<CommunalContentModel.WidgetContent.Widget> { + on { size } doReturn CommunalContentSize.Responsive(1) + } + + @Test + fun noOngoingContent() { + val list = listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized).containsExactly(mockWidget) + } + + @Test + fun singleOngoingContent_singleRowGrid() { + val list = createOngoingListWithSize(1) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 1) + + assertThat(resized.map { it.size }) + .containsExactly(CommunalContentSize.Responsive(1), mockWidget.size) + .inOrder() + } + + @Test + fun singleOngoingContent_twoRowGrid() { + val list = createOngoingListWithSize(1) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized.map { it.size }) + .containsExactly(CommunalContentSize.Responsive(2), mockWidget.size) + .inOrder() + } + + @Test + fun singleOngoingContent_threeRowGrid() { + val list = createOngoingListWithSize(1) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 3) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + // A spacer should be added as the second element to avoid mixing widget content + // with ongoing content. + assertThat(resized[1]).isInstanceOf(CommunalContentModel.Spacer::class.java) + } + + @Test + fun twoOngoingContent_singleRowGrid() { + val list = createOngoingListWithSize(2) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 1) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun twoOngoingContent_twoRowGrid() { + val list = createOngoingListWithSize(2) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun twoOngoingContent_threeRowGrid() { + val list = createOngoingListWithSize(2) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 3) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun threeOngoingContent_singleRowGrid() { + val list = createOngoingListWithSize(3) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 1) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun threeOngoingContent_twoRowGrid() { + val list = createOngoingListWithSize(3) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun threeOngoingContent_threeRowGrid() { + val list = createOngoingListWithSize(3) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 3) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun fourOngoingContent_singleRowGrid() { + val list = createOngoingListWithSize(4) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 1) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun fourOngoingContent_twoRowGrid() { + val list = createOngoingListWithSize(4) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 2) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + @Test + fun fourOngoingContent_threeRowGrid() { + val list = createOngoingListWithSize(4) + listOf(mockWidget) + val resized = resizeOngoingItems(list = list, numRows = 3) + + assertThat(resized.map { it.size }) + .containsExactly( + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + CommunalContentSize.Responsive(2), + CommunalContentSize.Responsive(1), + mockWidget.size, + ) + .inOrder() + } + + private fun createOngoingListWithSize(size: Int): List<CommunalContentModel.Ongoing> { + return List(size) { CommunalContentModel.Umo(createdTimestampMillis = 100) } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt index 18cc8bf5f0d3..5bbd3ffc625a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt @@ -172,16 +172,16 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { } @Test - fun selectedKey_onReorderWidgets_isSet() = + fun selectedKey_onReorderWidgets_isCleared() = testScope.runTest { val selectedKey by collectLastValue(underTest.selectedKey) - underTest.setSelectedKey(null) - assertThat(selectedKey).isNull() - val key = CommunalContentModel.KEY.widget(123) - underTest.onReorderWidgetStart(key) + underTest.setSelectedKey(key) assertThat(selectedKey).isEqualTo(key) + + underTest.onReorderWidgetStart() + assertThat(selectedKey).isNull() } @Test @@ -234,7 +234,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { @Test fun reorderWidget_uiEventLogging_start() { - underTest.onReorderWidgetStart(CommunalContentModel.KEY.widget(123)) + underTest.onReorderWidgetStart() verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START) } 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 92c76ff68b60..969dacec65a1 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 @@ -543,12 +543,12 @@ object TestShortcuts { simpleShortcutCategory( MultiTasking, "Split screen", - "Switch from split screen to full screen", + "Switch to full screen", ), simpleShortcutCategory( MultiTasking, "Split screen", - "Use split screen with current app on the left", + "Use split screen with app on the left", ), simpleShortcutCategory( MultiTasking, @@ -558,7 +558,7 @@ object TestShortcuts { simpleShortcutCategory( MultiTasking, "Split screen", - "Use split screen with current app on the right", + "Use split screen with app on the right", ), simpleShortcutCategory( MultiTasking, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt index 3f4a13414e96..b921ff7063a5 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt @@ -18,8 +18,9 @@ package com.android.systemui.qs.tiles import android.net.ConnectivityManager import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.telephony.flags.Flags @@ -31,6 +32,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl @@ -51,11 +53,17 @@ import org.mockito.MockitoAnnotations import org.mockito.kotlin.any import org.mockito.kotlin.times import org.mockito.kotlin.verify +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class AirplaneModeTileTest : SysuiTestCase() { +class AirplaneModeTileTest(flags: FlagsParameterization) : SysuiTestCase() { + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } @Mock private lateinit var mHost: QSHost @Mock private lateinit var mMetricsLogger: MetricsLogger @@ -149,4 +157,12 @@ class AirplaneModeTileTest : SysuiTestCase() { QSTileImpl.ResourceIcon.get(resId) } } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt index ae003497f9e9..cf9ef4d7c2a2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt @@ -18,9 +18,10 @@ package com.android.systemui.qs.tiles import android.content.Context import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -31,6 +32,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl @@ -51,14 +53,26 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @RunWithLooper(setAsMainLooper = true) @SmallTest -class BatterySaverTileTest : SysuiTestCase() { +class BatterySaverTileTest(flagsParameterization: FlagsParameterization) : SysuiTestCase() { companion object { private const val USER = 10 + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } + + init { + mSetFlagsRule.setFlagsParameterization(flagsParameterization) } @Mock private lateinit var userContext: Context diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt index 31519c584daa..6bb671315640 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt @@ -17,10 +17,11 @@ package com.android.systemui.qs.tiles import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.provider.Settings import android.safetycenter.SafetyCenterManager import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -30,6 +31,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLoggerFake +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl @@ -45,15 +47,27 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class CameraToggleTileTest : SysuiTestCase() { +class CameraToggleTileTest(flags: FlagsParameterization) : SysuiTestCase() { companion object { /* isBlocked */ const val CAMERA_TOGGLE_ENABLED: Boolean = false const val CAMERA_TOGGLE_DISABLED: Boolean = true + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } + + init { + mSetFlagsRule.setFlagsParameterization(flags) } @Mock private lateinit var host: QSHost diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java index 2c796a93613a..a58dd6301e07 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java @@ -16,6 +16,10 @@ package com.android.systemui.qs.tiles; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -25,10 +29,10 @@ import static org.mockito.Mockito.when; import android.content.Intent; import android.os.Handler; +import android.platform.test.flag.junit.FlagsParameterization; import android.provider.Settings; import android.testing.TestableLooper; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; @@ -55,13 +59,23 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -@RunWith(AndroidJUnit4.class) +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + +@RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class ColorInversionTileTest extends SysuiTestCase { private static final Integer COLOR_INVERSION_DISABLED = 0; private static final Integer COLOR_INVERSION_ENABLED = 1; + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + @Mock private QSHost mHost; @Mock @@ -81,6 +95,11 @@ public class ColorInversionTileTest extends SysuiTestCase { private SecureSettings mSecureSettings; private ColorInversionTile mTile; + public ColorInversionTileTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt index 23be9da106d9..27fd2818ea88 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DataSaverTileTest.kt @@ -17,8 +17,9 @@ package com.android.systemui.qs.tiles import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -29,6 +30,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl @@ -44,11 +46,17 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class DataSaverTileTest : SysuiTestCase() { +class DataSaverTileTest(flags: FlagsParameterization) : SysuiTestCase() { + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } @Mock private lateinit var mHost: QSHost @Mock private lateinit var mMetricsLogger: MetricsLogger @@ -121,4 +129,12 @@ class DataSaverTileTest : SysuiTestCase() { QSTileImpl.ResourceIcon.get(resId) } } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt index 33748b973f1c..9e4cf94df3de 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt @@ -20,11 +20,14 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Handler +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.provider.Settings import android.service.quicksettings.Tile import android.testing.TestableLooper import androidx.lifecycle.LifecycleOwner -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -43,7 +46,9 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.res.R import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture @@ -67,11 +72,17 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @SmallTest -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) -class DeviceControlsTileTest : SysuiTestCase() { +class DeviceControlsTileTest(flags: FlagsParameterization) : SysuiTestCase() { + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } @Mock private lateinit var qsHost: QSHost @Mock private lateinit var metricsLogger: MetricsLogger @@ -151,7 +162,7 @@ class DeviceControlsTileTest : SysuiTestCase() { } `when`(controlsComponent.getTileTitleId()).thenReturn(R.string.quick_controls_title) - `when`(controlsComponent.getTileTitleId()).thenReturn(R.drawable.controls_icon) + `when`(controlsComponent.getTileImageId()).thenReturn(R.drawable.controls_icon) } @Test @@ -378,6 +389,28 @@ class DeviceControlsTileTest : SysuiTestCase() { assertThat(tile.tileLabel).isEqualTo(context.getText(controlsComponent.getTileTitleId())) } + @Test + @DisableFlags(QSComposeFragment.FLAG_NAME) + fun tileIconEqualsResourceFromComponent_composeFlagDisabled() { + tile.refreshState() + testableLooper.processAllMessages() + assertThat(tile.state.icon).isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.controls_icon)) + } + + @Test + @EnableFlags(QSComposeFragment.FLAG_NAME) + fun tileIconEqualsResourceFromComponent_composeFlagEnable() { + tile.refreshState() + testableLooper.processAllMessages() + assertThat(tile.state.icon) + .isEqualTo( + QSTileImpl.DrawableIconWithRes( + mContext.getDrawable(R.drawable.controls_icon), + R.drawable.controls_icon, + ) + ) + } + private fun createTile(): DeviceControlsTile { return DeviceControlsTile( qsHost, @@ -396,6 +429,14 @@ class DeviceControlsTileTest : SysuiTestCase() { testableLooper.processAllMessages() } } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } } private const val CONTROLS_ACTIVITY_CLASS_NAME = "com.android.systemui.controls.ui.ControlsActivity" diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt index 3cb9091459d9..6a15a5bc21e2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FlashlightTileTest.kt @@ -1,9 +1,9 @@ package com.android.systemui.qs.tiles -import android.content.Context import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -13,6 +13,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl @@ -27,13 +28,17 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class FlashlightTileTest : SysuiTestCase() { +class FlashlightTileTest(flags: FlagsParameterization) : SysuiTestCase() { - @Mock private lateinit var mockContext: Context + init { + mSetFlagsRule.setFlagsParameterization(flags) + } @Mock private lateinit var qsLogger: QSLogger @@ -58,7 +63,7 @@ class FlashlightTileTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) - Mockito.`when`(qsHost.context).thenReturn(mockContext) + Mockito.`when`(qsHost.context).thenReturn(mContext) tile = FlashlightTile( @@ -122,4 +127,12 @@ class FlashlightTileTest : SysuiTestCase() { QSTileImpl.ResourceIcon.get(resId) } } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt index f33de4d9144d..eeccbdf20540 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileNewImplTest.kt @@ -17,10 +17,11 @@ package com.android.systemui.qs.tiles import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.service.quicksettings.Tile import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -29,6 +30,7 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tiles.dialog.InternetDialogManager import com.android.systemui.qs.tiles.dialog.WifiStateWorker @@ -62,12 +64,18 @@ import org.mockito.kotlin.eq import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWithLooper(setAsMainLooper = true) -@RunWith(AndroidJUnit4::class) -class InternetTileNewImplTest : SysuiTestCase() { +@RunWith(ParameterizedAndroidJunit4::class) +class InternetTileNewImplTest(flags: FlagsParameterization) : SysuiTestCase() { + init { + mSetFlagsRule.setFlagsParameterization(flags) + } + lateinit var underTest: InternetTileNewImpl private val testDispatcher = StandardTestDispatcher() @@ -252,5 +260,11 @@ class InternetTileNewImplTest : SysuiTestCase() { const val WIFI_SSID = "test ssid" val ACTIVE_WIFI = WifiNetworkModel.Active.of(isValidated = true, level = 4, ssid = WIFI_SSID) + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java index b5a64b39f7ce..d7b183ed7def 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/InternetTileTest.java @@ -16,6 +16,10 @@ package com.android.systemui.qs.tiles; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.eq; @@ -25,10 +29,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.os.Handler; +import android.platform.test.flag.junit.FlagsParameterization; import android.service.quicksettings.Tile; import android.testing.TestableLooper; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; @@ -57,11 +61,21 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -@RunWith(AndroidJUnit4.class) +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + +@RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class InternetTileTest extends SysuiTestCase { + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + @Mock private QSHost mHost; @Mock @@ -78,6 +92,11 @@ public class InternetTileTest extends SysuiTestCase { private TestableLooper mTestableLooper; private InternetTile mTile; + public InternetTileTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/LocationTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/LocationTileTest.kt index 4be189964d6b..a581b57ac44f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/LocationTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/LocationTileTest.kt @@ -16,10 +16,10 @@ package com.android.systemui.qs.tiles -import android.content.Context import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -29,6 +29,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor @@ -48,13 +49,18 @@ import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class LocationTileTest : SysuiTestCase() { +class LocationTileTest(flags: FlagsParameterization) : SysuiTestCase() { + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } - @Mock private lateinit var mockContext: Context @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var qsHost: QSHost @Mock private lateinit var metricsLogger: MetricsLogger @@ -73,7 +79,7 @@ class LocationTileTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) - `when`(qsHost.context).thenReturn(mockContext) + `when`(qsHost.context).thenReturn(mContext) tile = LocationTile( @@ -139,4 +145,12 @@ class LocationTileTest : SysuiTestCase() { QSTileImpl.ResourceIcon.get(resId) } } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt index afe9713538de..a39692d10863 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt @@ -17,10 +17,11 @@ package com.android.systemui.qs.tiles import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.provider.Settings import android.safetycenter.SafetyCenterManager import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -30,6 +31,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl @@ -45,15 +47,27 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class MicrophoneToggleTileTest : SysuiTestCase() { +class MicrophoneToggleTileTest(flags: FlagsParameterization) : SysuiTestCase() { companion object { /* isBlocked */ const val MICROPHONE_TOGGLE_ENABLED: Boolean = false const val MICROPHONE_TOGGLE_DISABLED: Boolean = true + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } + + init { + mSetFlagsRule.setFlagsParameterization(flags) } @Mock private lateinit var host: QSHost diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt index 69dab39b279c..a193cbcec114 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/NightDisplayTileTest.kt @@ -19,8 +19,9 @@ package com.android.systemui.qs.tiles import android.hardware.display.ColorDisplayManager import android.hardware.display.NightDisplayListener import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -31,6 +32,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl @@ -46,11 +48,18 @@ import org.mockito.Mock import org.mockito.Mockito.anyInt import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class NightDisplayTileTest : SysuiTestCase() { +class NightDisplayTileTest(flags: FlagsParameterization) : SysuiTestCase() { + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } + @Mock private lateinit var mHost: QSHost @Mock private lateinit var mMetricsLogger: MetricsLogger @@ -135,4 +144,12 @@ class NightDisplayTileTest : SysuiTestCase() { QSTileImpl.ResourceIcon.get(resId) } } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java index 2345128e8c84..c24498411ff7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ReduceBrightColorsTileTest.java @@ -16,6 +16,10 @@ package com.android.systemui.qs.tiles; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; + import static junit.framework.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; @@ -28,10 +32,10 @@ import static org.mockito.Mockito.when; import android.os.Handler; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.FlagsParameterization; import android.service.quicksettings.Tile; import android.testing.TestableLooper; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.R; @@ -59,10 +63,21 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -@RunWith(AndroidJUnit4.class) +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + +@RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class ReduceBrightColorsTileTest extends SysuiTestCase { + + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + @Mock private QSHost mHost; @Mock @@ -85,6 +100,11 @@ public class ReduceBrightColorsTileTest extends SysuiTestCase { private TestableLooper mTestableLooper; private ReduceBrightColorsTile mTile; + public ReduceBrightColorsTileTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); 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 7fb0eabe96e5..fee358a7c15d 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 @@ -17,6 +17,9 @@ package com.android.systemui.qs.tiles; import static android.hardware.SensorPrivacyManager.Sensors.CAMERA; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; import static junit.framework.TestCase.assertEquals; @@ -27,10 +30,10 @@ import android.Manifest; import android.content.pm.PackageManager; import android.hardware.SensorPrivacyManager; import android.os.Handler; +import android.platform.test.flag.junit.FlagsParameterization; import android.testing.TestableLooper; import android.testing.TestableResources; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; @@ -59,7 +62,12 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -@RunWith(AndroidJUnit4.class) +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + +@RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class RotationLockTileTest extends SysuiTestCase { @@ -70,6 +78,11 @@ public class RotationLockTileTest extends SysuiTestCase { "1:2" }; + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + @Mock private PackageManager mPackageManager; @Mock @@ -98,6 +111,11 @@ public class RotationLockTileTest extends SysuiTestCase { private RotationLockTile mLockTile; private TestableResources mTestableResources; + public RotationLockTileTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java index a7c7a78dae5f..fc1d73b62abd 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java @@ -16,6 +16,10 @@ package com.android.systemui.qs.tiles; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; @@ -31,10 +35,10 @@ import static org.mockito.Mockito.when; import android.app.Dialog; import android.media.projection.StopReason; import android.os.Handler; +import android.platform.test.flag.junit.FlagsParameterization; import android.service.quicksettings.Tile; import android.testing.TestableLooper; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; @@ -66,11 +70,21 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -@RunWith(AndroidJUnit4.class) +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + +@RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class ScreenRecordTileTest extends SysuiTestCase { + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + @Mock private RecordingController mController; @Mock @@ -105,6 +119,11 @@ public class ScreenRecordTileTest extends SysuiTestCase { private TestableLooper mTestableLooper; private ScreenRecordTile mTile; + public ScreenRecordTileTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt index 773e225a6a35..3246e6490799 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/UiModeNightTileTest.kt @@ -17,12 +17,11 @@ package com.android.systemui.qs.tiles import android.app.UiModeManager -import android.content.Context import android.content.res.Configuration -import android.content.res.Resources import android.os.Handler +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.testing.TestableLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.systemui.SysuiTestCase @@ -32,6 +31,7 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl @@ -48,15 +48,19 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest -class UiModeNightTileTest : SysuiTestCase() { +class UiModeNightTileTest(flags: FlagsParameterization) : SysuiTestCase() { + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } - @Mock private lateinit var mockContext: Context @Mock private lateinit var uiModeManager: UiModeManager - @Mock private lateinit var resources: Resources @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var qsHost: QSHost @Mock private lateinit var metricsLogger: MetricsLogger @@ -70,19 +74,19 @@ class UiModeNightTileTest : SysuiTestCase() { private val falsingManager = FalsingManagerFake() private lateinit var testableLooper: TestableLooper private lateinit var tile: UiModeNightTile - private lateinit var configuration: Configuration + private val configuration = Configuration() @Before fun setUp() { MockitoAnnotations.initMocks(this) + val initialConfiguration = mContext.resources.configuration + onTeardown { mContext.resources.configuration.updateFrom(initialConfiguration) } + testableLooper = TestableLooper.get(this) - configuration = Configuration() mContext.addMockSystemService(UiModeManager::class.java, uiModeManager) - `when`(qsHost.context).thenReturn(mockContext) + `when`(qsHost.context).thenReturn(mContext) `when`(qsHost.userContext).thenReturn(mContext) - `when`(mockContext.resources).thenReturn(resources) - `when`(resources.configuration).thenReturn(configuration) tile = UiModeNightTile( @@ -118,7 +122,7 @@ class UiModeNightTileTest : SysuiTestCase() { } @Test - fun testIcon_whenNightModeOn_isOffState() { + fun testIcon_whenNightModeOff_isOffState() { val state = QSTile.BooleanState() setNightModeOff() @@ -131,11 +135,13 @@ class UiModeNightTileTest : SysuiTestCase() { private fun setNightModeOn() { `when`(uiModeManager.nightMode).thenReturn(UiModeManager.MODE_NIGHT_YES) configuration.uiMode = Configuration.UI_MODE_NIGHT_YES + mContext.resources.configuration.updateFrom(configuration) } private fun setNightModeOff() { `when`(uiModeManager.nightMode).thenReturn(UiModeManager.MODE_NIGHT_NO) configuration.uiMode = Configuration.UI_MODE_NIGHT_NO + mContext.resources.configuration.updateFrom(configuration) } private fun createExpectedIcon(resId: Int): QSTile.Icon { @@ -145,4 +151,12 @@ class UiModeNightTileTest : SysuiTestCase() { QSTileImpl.ResourceIcon.get(resId) } } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt index 52c476ec92cc..e4a988860a6e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractorTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.statusbar.connectivity.AccessPointController import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.nullable import com.google.common.truth.Truth +import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -136,4 +137,13 @@ class InternetTileUserActionInteractorTest : SysuiTestCase() { verify(wifiStateWorker, times(1)).isWifiEnabled = eq(true) } + + @Test + fun detailsViewModel() = + kosmos.testScope.runTest { + assertThat(underTest.detailsViewModel.getTitle()) + .isEqualTo("Internet") + assertThat(underTest.detailsViewModel.getSubTitle()) + .isEqualTo("Tab a network to connect") + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt index 954215eede0d..2edb9c60711b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt @@ -173,6 +173,21 @@ class QSTileViewModelTest : SysuiTestCase() { .isEqualTo(FakeQSTileDataInteractor.AvailabilityRequest(USER)) } + @Test + fun tileDetails() = + testScope.runTest { + assertThat(tileUserActionInteractor.detailsViewModel).isNotNull() + assertThat(tileUserActionInteractor.detailsViewModel?.getTitle()) + .isEqualTo("FakeQSTileUserActionInteractor") + assertThat(underTest.detailsViewModel).isNotNull() + assertThat(underTest.detailsViewModel?.getTitle()) + .isEqualTo("FakeQSTileUserActionInteractor") + + tileUserActionInteractor.detailsViewModel = null + assertThat(tileUserActionInteractor.detailsViewModel).isNull() + assertThat(underTest.detailsViewModel).isNull() + } + private fun createViewModel( scope: TestScope, config: QSTileConfig = tileConfig, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt index 7842d75db6c4..f9b44886ec3e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/CommunalSmartspaceControllerTest.kt @@ -111,6 +111,8 @@ class CommunalSmartspaceControllerTest : SysuiTestCase() { override fun getCurrentCardTopPadding(): Int { return 0 } + + override fun setHorizontalPaddings(horizontalPadding: Int) {} } @Before diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt index c83c82dc0914..70ba00e82241 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt @@ -127,6 +127,8 @@ class DreamSmartspaceControllerTest : SysuiTestCase() { override fun getCurrentCardTopPadding(): Int { return 0 } + + override fun setHorizontalPaddings(horizontalPadding: Int) {} } @Before diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt index fe287ef98729..611ae3dbefcf 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt @@ -1109,6 +1109,9 @@ class LockscreenSmartspaceControllerTest : SysuiTestCase() { override fun getCurrentCardTopPadding(): Int { return 0 } + + override fun setHorizontalPaddings(horizontalPadding: Int) { + } }) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt index 68798a88eecc..9e7befd3cf92 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt @@ -27,15 +27,28 @@ import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.FlagsParameterization import android.service.notification.StatusBarNotification import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.SceneKey import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.keyguardUpdateMonitor import com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING import com.android.systemui.SysuiTestCase +import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository +import com.android.systemui.authentication.shared.model.AuthenticationMethodModel +import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor +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.fakeDeviceEntryFaceAuthRepository +import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.statusbar.fakeStatusBarStateController import com.android.systemui.plugins.statusbar.statusBarStateController import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.RankingBuilder import com.android.systemui.statusbar.StatusBarState @@ -60,11 +73,16 @@ import com.android.systemui.statusbar.policy.sensitiveNotificationProtectionCont import com.android.systemui.testKosmos import com.android.systemui.util.mockito.withArgCaptor import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never @@ -86,6 +104,8 @@ class SensitiveContentCoordinatorTest(flags: FlagsParameterization) : SysuiTestC statusBarStateController = fakeStatusBarStateController } + val testScope = kosmos.testScope + val dynamicPrivacyController: DynamicPrivacyController = kosmos.mockDynamicPrivacyController val lockscreenUserManager: NotificationLockscreenUserManager = kosmos.notificationLockscreenUserManager @@ -95,7 +115,12 @@ class SensitiveContentCoordinatorTest(flags: FlagsParameterization) : SysuiTestC kosmos.fakeStatusBarStateController val sensitiveNotificationProtectionController: SensitiveNotificationProtectionController = kosmos.mockSensitiveNotificationProtectionController - val sceneInteractor: SceneInteractor = kosmos.sceneInteractor + val deviceEntryInteractor: DeviceEntryInteractor + get() = kosmos.deviceEntryInteractor + + val faceAuthRepository = kosmos.fakeDeviceEntryFaceAuthRepository + val sceneInteractor: SceneInteractor + get() = kosmos.sceneInteractor val coordinator: SensitiveContentCoordinator by lazy { kosmos.sensitiveContentCoordinator } @@ -112,592 +137,696 @@ class SensitiveContentCoordinatorTest(flags: FlagsParameterization) : SysuiTestC } @Test - fun onDynamicPrivacyChanged_invokeInvalidationListener() { - coordinator.attach(pipeline) - val invalidator = - withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } - val dynamicPrivacyListener = - withArgCaptor<DynamicPrivacyController.Listener> { - verify(dynamicPrivacyController).addListener(capture()) - } - - val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() - invalidator.setInvalidationListener(invalidationListener) - - dynamicPrivacyListener.onDynamicPrivacyChanged() + @EnableSceneContainer + fun onLockscreenDynamicallyUnlocked_invokeInvalidationListener() = + testScope.runTest { + // Setup + coordinator.attach(pipeline) + val invalidator = + withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } + val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() + invalidator.setInvalidationListener(invalidationListener) + + // Given the lockscreen is shown + setupLockScreen(canSwipeUp = false) + clearInvocations(invalidationListener) + + // When the device gets unlocked + faceAuthRepository.isAuthenticated.value = true + runCurrent() + + // Then the invalidationListener is called + verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) + } - verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) - } + @Test + @DisableSceneContainer + fun onDynamicPrivacyChanged_invokeInvalidationListener() = + testScope.runTest { + coordinator.attach(pipeline) + val invalidator = + withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } + val dynamicPrivacyListener = + withArgCaptor<DynamicPrivacyController.Listener> { + verify(dynamicPrivacyController).addListener(capture()) + } + + val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() + invalidator.setInvalidationListener(invalidationListener) + + dynamicPrivacyListener.onDynamicPrivacyChanged() + + verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onSensitiveStateChanged_invokeInvalidationListener() { - coordinator.attach(pipeline) - val invalidator = - withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } - val onSensitiveStateChangedListener = - withArgCaptor<Runnable> { - verify(sensitiveNotificationProtectionController) - .registerSensitiveStateListener(capture()) - } - - val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() - invalidator.setInvalidationListener(invalidationListener) - - onSensitiveStateChangedListener.run() - - verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) - } + fun onSensitiveStateChanged_invokeInvalidationListener() = + testScope.runTest { + coordinator.attach(pipeline) + val invalidator = + withArgCaptor<Invalidator> { verify(pipeline).addPreRenderInvalidator(capture()) } + val onSensitiveStateChangedListener = + withArgCaptor<Runnable> { + verify(sensitiveNotificationProtectionController) + .registerSensitiveStateListener(capture()) + } + + val invalidationListener = mock<Pluggable.PluggableListener<Invalidator>>() + invalidator.setInvalidationListener(invalidationListener) + + onSensitiveStateChangedListener.run() + + verify(invalidationListener).onPluggableInvalidated(eq(invalidator), any()) + } @Test @DisableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun screenshareSecretFilter_flagDisabled_filterNoAdded() { - coordinator.attach(pipeline) + fun screenshareSecretFilter_flagDisabled_filterNoAdded() = + testScope.runTest { + coordinator.attach(pipeline) - verify(pipeline, never()).addFinalizeFilter(any()) - } + verify(pipeline, never()).addFinalizeFilter(any()) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun screenshareSecretFilter_sensitiveInctive_noFiltersSecret() { - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(false) - - coordinator.attach(pipeline) - val filter = withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) } - - val defaultNotification = createNotificationEntry("test", false, false) - val notificationWithSecretVisibility = createNotificationEntry("test", true, false) - val notificationOnSecretChannel = createNotificationEntry("test", false, true) - - assertFalse(filter.shouldFilterOut(defaultNotification, 0)) - assertFalse(filter.shouldFilterOut(notificationWithSecretVisibility, 0)) - assertFalse(filter.shouldFilterOut(notificationOnSecretChannel, 0)) - } + fun screenshareSecretFilter_sensitiveInctive_noFiltersSecret() = + testScope.runTest { + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(false) + + coordinator.attach(pipeline) + val filter = + withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) } + + val defaultNotification = createNotificationEntry("test", false, false) + val notificationWithSecretVisibility = createNotificationEntry("test", true, false) + val notificationOnSecretChannel = createNotificationEntry("test", false, true) + + assertFalse(filter.shouldFilterOut(defaultNotification, 0)) + assertFalse(filter.shouldFilterOut(notificationWithSecretVisibility, 0)) + assertFalse(filter.shouldFilterOut(notificationOnSecretChannel, 0)) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun screenshareSecretFilter_sensitiveActive_filtersSecret() { - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - coordinator.attach(pipeline) - val filter = withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) } - - val defaultNotification = createNotificationEntry("test", false, false) - val notificationWithSecretVisibility = createNotificationEntry("test", true, false) - val notificationOnSecretChannel = createNotificationEntry("test", false, true) - - assertFalse(filter.shouldFilterOut(defaultNotification, 0)) - assertTrue(filter.shouldFilterOut(notificationWithSecretVisibility, 0)) - assertTrue(filter.shouldFilterOut(notificationOnSecretChannel, 0)) - } + fun screenshareSecretFilter_sensitiveActive_filtersSecret() = + testScope.runTest { + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + coordinator.attach(pipeline) + val filter = + withArgCaptor<NotifFilter> { verify(pipeline).addFinalizeFilter(capture()) } + + val defaultNotification = createNotificationEntry("test", false, false) + val notificationWithSecretVisibility = createNotificationEntry("test", true, false) + val notificationOnSecretChannel = createNotificationEntry("test", false, true) + + assertFalse(filter.shouldFilterOut(defaultNotification, 0)) + assertTrue(filter.shouldFilterOut(notificationWithSecretVisibility, 0)) + assertTrue(filter.shouldFilterOut(notificationOnSecretChannel, 0)) + } @Test - fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, false) - } + fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, false) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceUnlocked_notifDoesNotNeedRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, false) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, false) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, false) - } + fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, false) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceUnlocked_notifWouldNeedRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(false) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, false) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, false) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, false) - } + fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, false) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(true) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceLocked_userAllowsPublicNotifs_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(true) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, false) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, false) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - } + fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) @Suppress("ktlint:standard:max-line-length") - fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) @Suppress("ktlint:standard:max-line-length") - fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, false) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceLocked_userDisallowsPublicNotifs_notifDoesNotNeedRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, false) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceLocked_notifNeedsRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(true, true) - } + fun onBeforeRenderList_deviceLocked_notifNeedsRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(true, true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceLocked_notifNeedsRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceLocked_notifNeedsRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceLocked_notifNeedsRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(false) - val entry = fakeNotification(1, true) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceLocked_notifNeedsRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = false) + val entry = fakeNotification(1, true) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - val entry = fakeNotification(1, true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + val entry = fakeNotification(1, true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - val entry = fakeNotification(1, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(false, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + val entry = fakeNotification(1, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(false, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) @Suppress("ktlint:standard:max-line-length") - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - val entry = fakeNotification(1, true) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifNeedsRedaction_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + val entry = fakeNotification(1, true) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) - val entry = fakeNotification(2, true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(true, true) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) + val entry = fakeNotification(2, true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(true, true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge_sensitiveActive() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) - val entry = fakeNotification(2, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge_sensitiveActive() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) + val entry = fakeNotification(2, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(true) + } @Test @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING) @Suppress("ktlint:standard:max-line-length") - fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge_shouldProtectNotification() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } - - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) - val entry = fakeNotification(2, true) - whenever( - sensitiveNotificationProtectionController.shouldProtectNotification( - entry.getRepresentativeEntry() + fun onBeforeRenderList_deviceDynamicallyUnlocked_notifUserNeedsWorkChallenge_shouldProtectNotification() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + whenever(lockscreenUserManager.needsSeparateWorkChallenge(2)).thenReturn(true) + val entry = fakeNotification(2, true) + whenever( + sensitiveNotificationProtectionController.shouldProtectNotification( + entry.getRepresentativeEntry() + ) ) - ) - .thenReturn(true) + .thenReturn(true) - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - verify(entry.representativeEntry!!).setSensitive(true, true) - verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) - } + verify(entry.representativeEntry!!).setSensitive(true, true) + verify(entry.representativeEntry!!.row!!).setPublicExpanderVisible(false) + } @Test - fun onBeforeRenderList_deviceDynamicallyUnlocked_deviceBiometricBypassingLockScreen() { - coordinator.attach(pipeline) - val onBeforeRenderListListener = - withArgCaptor<OnBeforeRenderListListener> { - verify(pipeline).addOnBeforeRenderListListener(capture()) - } + fun onBeforeRenderList_deviceDynamicallyUnlocked_deviceBiometricBypassingLockScreen() = + testScope.runTest { + coordinator.attach(pipeline) + val onBeforeRenderListListener = + withArgCaptor<OnBeforeRenderListListener> { + verify(pipeline).addOnBeforeRenderListListener(capture()) + } + + whenever(lockscreenUserManager.currentUserId).thenReturn(1) + whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) + whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)) + .thenReturn(false) + setupLockScreen(canSwipeUp = true) + whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(any())) + .thenReturn(true) + val entry = fakeNotification(2, true) + whenever(sensitiveNotificationProtectionController.isSensitiveStateActive) + .thenReturn(true) + whenever(sensitiveNotificationProtectionController.shouldProtectNotification(any())) + .thenReturn(true) + statusBarStateController.state = StatusBarState.KEYGUARD + + onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) + + verify(entry.representativeEntry!!, never()).setSensitive(any(), any()) + verify(entry.representativeEntry!!.row!!, never()).setPublicExpanderVisible(any()) + } + + private fun TestScope.setupLockScreen(canSwipeUp: Boolean) { + if (SceneContainerFlag.isEnabled) { + val authMethod = + if (canSwipeUp) AuthenticationMethodModel.None + else AuthenticationMethodModel.Password + kosmos.fakeAuthenticationRepository.setAuthenticationMethod(authMethod) + kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) + switchToScene(Scenes.Lockscreen) + } else { + whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(canSwipeUp) + } + } - whenever(lockscreenUserManager.currentUserId).thenReturn(1) - whenever(lockscreenUserManager.isLockscreenPublicMode(1)).thenReturn(true) - whenever(lockscreenUserManager.userAllowsPrivateNotificationsInPublic(1)).thenReturn(false) - whenever(dynamicPrivacyController.isDynamicallyUnlocked).thenReturn(true) - whenever(keyguardUpdateMonitor.getUserUnlockedWithBiometricAndIsBypassing(any())) - .thenReturn(true) - val entry = fakeNotification(2, true) - whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) - whenever(sensitiveNotificationProtectionController.shouldProtectNotification(any())) - .thenReturn(true) - statusBarStateController.state = StatusBarState.KEYGUARD - - onBeforeRenderListListener.onBeforeRenderList(listOf(entry)) - - verify(entry.representativeEntry!!, never()).setSensitive(any(), any()) - verify(entry.representativeEntry!!.row!!, never()).setPublicExpanderVisible(any()) + private fun TestScope.switchToScene(sceneKey: SceneKey) { + sceneInteractor.changeScene(sceneKey, "reason") + sceneInteractor.setTransitionState(flowOf(ObservableTransitionState.Idle(sceneKey))) + runCurrent() } private fun fakeNotification(notifUserId: Int, needsRedaction: Boolean): ListEntry { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt index c0a206afe64b..9ad23154c334 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt @@ -49,11 +49,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { private val dispatcher = StandardTestDispatcher() private val testScope = TestScope(dispatcher) - private val iconsInteractor = - FakeMobileIconsInteractor( - FakeMobileMappingsProxy(), - mock(), - ) + private val iconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock()) private val repo = FakeDeviceBasedSatelliteRepository() private val connectivityRepository = FakeConnectivityRepository() @@ -515,7 +511,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { // GIVEN, 2 connection val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1) - val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(1) + val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2) // WHEN all connections are NOT OOS. i1.isInService.value = true @@ -547,7 +543,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { // GIVEN a condition that should return true (all conections OOS) val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1) - val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(1) + val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2) i1.isInService.value = true i2.isInService.value = true @@ -579,4 +575,40 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { // THEN the interactor returns true due to the wifi network being active assertThat(latest).isTrue() } + + @Test + @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG) + fun isAnyConnectionNtn_trueWhenAnyNtn() = + testScope.runTest { + val latest by collectLastValue(underTest.isAnyConnectionNtn) + + // GIVEN, 2 connection + val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1) + val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2) + + // WHEN at least one connection is using ntn + i1.isNonTerrestrial.value = true + i2.isNonTerrestrial.value = false + + // THEN the value is propagated to this interactor + assertThat(latest).isTrue() + } + + @Test + @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG) + fun isAnyConnectionNtn_falseWhenNoNtn() = + testScope.runTest { + val latest by collectLastValue(underTest.isAnyConnectionNtn) + + // GIVEN, 2 connection + val i1 = iconsInteractor.getMobileConnectionInteractorForSubId(1) + val i2 = iconsInteractor.getMobileConnectionInteractorForSubId(2) + + // WHEN at no connection is using ntn + i1.isNonTerrestrial.value = false + i2.isNonTerrestrial.value = false + + // THEN the value is propagated to this interactor + assertThat(latest).isFalse() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt index 509aa7ad67fd..fe5b56a4e66d 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt @@ -327,10 +327,11 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { // GIVEN satellite is allowed repo.isSatelliteAllowedForCurrentLocation.value = true - // GIVEN all icons are OOS + // GIVEN all icons are OOS and not ntn val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) i1.isInService.value = false i1.isEmergencyOnly.value = false + i1.isNonTerrestrial.value = false // GIVEN apm is disabled airplaneModeRepository.setIsAirplaneMode(false) @@ -344,6 +345,29 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { } @Test + fun icon_nullWhenConnected_mobileNtnConnectionExists() = + testScope.runTest { + val latest by collectLastValue(underTest.icon) + + // GIVEN satellite is allowed + repo.isSatelliteAllowedForCurrentLocation.value = true + + // GIVEN ntn connection exists + val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) + i1.isNonTerrestrial.value = true + + // GIVEN apm is disabled + airplaneModeRepository.setIsAirplaneMode(false) + + // GIVEN satellite reports that it is Connected + repo.connectionState.value = SatelliteConnectionState.On + + // THEN icon is null because despite being connected, the mobile stack is reporting a + // nonTerrestrial network, and therefore will have its own icon + assertThat(latest).isNull() + } + + @Test fun icon_satelliteIsProvisioned() = testScope.runTest { val latest by collectLastValue(underTest.icon) diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java index dcb15a7cd9aa..b2083c2921c9 100644 --- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java +++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java @@ -213,6 +213,13 @@ public interface BcSmartspaceDataPlugin extends Plugin { default int getCurrentCardTopPadding() { throw new UnsupportedOperationException("Not implemented by " + getClass()); } + + /** + * Set the horizontal paddings for applicable children inside the SmartspaceView. + */ + default void setHorizontalPaddings(int horizontalPadding) { + throw new UnsupportedOperationException("Not implemented by " + getClass()); + } } /** Interface for launching Intents, which can differ on the lockscreen */ diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml index ba0d7de1d481..bfb37a0d97a7 100644 --- a/packages/SystemUI/res-keyguard/values/dimens.xml +++ b/packages/SystemUI/res-keyguard/values/dimens.xml @@ -110,6 +110,7 @@ <dimen name="below_clock_padding_start">32dp</dimen> <dimen name="below_clock_padding_end">16dp</dimen> <dimen name="below_clock_padding_start_icons">28dp</dimen> + <dimen name="smartspace_padding_horizontal">16dp</dimen> <!-- Proportion of the screen height to use to set the maximum height of the bouncer to when the device is in the DEVICE_POSTURE_HALF_OPENED posture, for the PIN/pattern entry. 0 will diff --git a/packages/SystemUI/res/drawable/ic_screensaver_auto.xml b/packages/SystemUI/res/drawable/ic_screensaver_auto.xml new file mode 100644 index 000000000000..7cccff624c6e --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_screensaver_auto.xml @@ -0,0 +1,26 @@ +<?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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@android:color/white" + android:pathData="M160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720L160,720Q160,720 160,720Q160,720 160,720L160,240Q160,240 160,240Q160,240 160,240L160,240Q160,240 160,240Q160,240 160,240Q160,240 160,240Q160,240 160,240ZM160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L440,160Q440,179 440,199Q440,219 440,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720L800,720Q800,720 800,720Q800,720 800,720L800,480Q823,480 843,480Q863,480 880,480L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM700,480Q700,388 636,324Q572,260 480,260Q572,260 636,196Q700,132 700,40Q700,132 764,196Q828,260 920,260Q828,260 764,324Q700,388 700,480Z"/> +</vector> diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index 2b40df47667a..5922a7dcdcf0 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -149,7 +149,8 @@ android:clickable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="start|center_vertical"> + android:minHeight="72dp" + android:gravity="center_vertical"> <TextView android:id="@+id/mobile_title" android:maxLines="1" diff --git a/packages/SystemUI/res/layout/volume_dialog_slider.xml b/packages/SystemUI/res/layout/volume_dialog_slider.xml index c1852b106544..9ac456c17084 100644 --- a/packages/SystemUI/res/layout/volume_dialog_slider.xml +++ b/packages/SystemUI/res/layout/volume_dialog_slider.xml @@ -14,15 +14,21 @@ limitations under the License. --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="@dimen/volume_dialog_slider_width" - android:layout_height="@dimen/volume_dialog_slider_height"> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> <com.google.android.material.slider.Slider - style="@style/SystemUI.Material3.Slider.Volume" android:id="@+id/volume_dialog_slider" - android:layout_width="@dimen/volume_dialog_slider_height" - android:layout_height="match_parent" + style="@style/SystemUI.Material3.Slider.Volume" + android:layout_width="@dimen/volume_dialog_slider_width" + android:layout_height="@dimen/volume_dialog_slider_height" android:layout_gravity="center" - android:rotation="270" - android:theme="@style/Theme.Material3.Light" /> -</FrameLayout> + android:theme="@style/Theme.Material3.Light" + android:orientation="vertical" + app:thumbHeight="52dp" + app:trackCornerSize="12dp" + app:trackHeight="40dp" + app:trackStopIndicatorSize="6dp" + app:trackInsideCornerSize="2dp" /> +</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index b91bfd6c9520..cef0316c23d3 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -38,7 +38,7 @@ <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Laat <xliff:g id="APPLICATION">%1$s</xliff:g> toe om by <xliff:g id="USB_DEVICE">%2$s</xliff:g> in te gaan?\nOpneemtoestemming is nie aan hierdie app verleen nie, maar dit kan oudio deur hierdie USB-toestel vasvang."</string> <string name="usb_audio_device_permission_prompt_title" msgid="4221351137250093451">"Gee <xliff:g id="APPLICATION">%1$s</xliff:g> toegang tot <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string> <string name="usb_audio_device_confirm_prompt_title" msgid="8828406516732985696">"Maak <xliff:g id="APPLICATION">%1$s</xliff:g> oop om <xliff:g id="USB_DEVICE">%2$s</xliff:g> te hanteer?"</string> - <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Opneemtoestemming is nie aan hierdie program verleen nie, maar dit kan oudio deur hierdie USB-toestel opneem. As jy <xliff:g id="APPLICATION">%1$s</xliff:g> met hierdie toestel gebruik, kan dit verhinder dat jy oproepe, kennisgewings en wekkers hoor."</string> + <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Opneemtoestemming is nie aan hierdie app verleen nie, maar dit kan oudio deur hierdie USB-toestel opneem. As jy <xliff:g id="APPLICATION">%1$s</xliff:g> met hierdie toestel gebruik, kan dit verhinder dat jy oproepe, kennisgewings en wekkers hoor."</string> <string name="usb_audio_device_prompt" msgid="7944987408206252949">"As jy <xliff:g id="APPLICATION">%1$s</xliff:g> met hierdie toestel gebruik, kan dit verhinder dat jy oproepe, kennisgewings en wekkers hoor."</string> <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"Gee <xliff:g id="APPLICATION">%1$s</xliff:g> toegang tot <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string> <string name="usb_device_confirm_prompt" msgid="4091711472439910809">"Hanteer <xliff:g id="USB_DEVICE">%2$s</xliff:g> met <xliff:g id="APPLICATION">%1$s</xliff:g>?"</string> @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Kennisgewings"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekke"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vee alle stil kennisgewings uit"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kennisgewings onderbreek deur Moenie Steur Nie"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Geen kennisgewings nie}=1{Kennisgewings is deur {mode} onderbreek}=2{Kennisgewings is deur {mode} en een ander modus onderbreek}other{Kennisgewings is deur {mode} en # ander modusse onderbreek}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Begin nou"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Kopnasporing"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tik om luiermodus te verander"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"luiermodus"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"demp"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ontdemp"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreer"</string> @@ -1203,8 +1207,8 @@ <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(ontkoppel)"</string> <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Kan nie wissel nie. Tik om weer te probeer."</string> <string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"Koppel ’n toestel"</string> - <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Maak die program oop om hierdie sessie uit te saai."</string> - <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende program"</string> + <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Maak die app oop om hierdie sessie uit te saai."</string> + <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Onbekende app"</string> <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Hou op uitsaai"</string> <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Beskikbare toestelle vir oudio-uitsette."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volume"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Druk die handelingsleutel op jou sleutelbord"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Welgedaan!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Jy het die Bekyk Onlangse Apps-gebaar voltooi"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Sleutelbordlig"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Vlak %1$d van %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Huiskontroles"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index cf73b71168b9..5f7774394862 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ምግብር በመጠቀም መተግበሪያ ለመክፈት እርስዎ መሆንዎን ማረጋገጥ አለብዎት። እንዲሁም የእርስዎ ጡባዊ በተቆለፈበት ጊዜ እንኳን ማንኛውም ሰው እነሱን ማየት እንደሚችል ከግምት ውስጥ ያስገቡ። አንዳንድ ምግብሮች ለማያ ገፅ ቁልፍዎ የታሰቡ ላይሆኑ ይችላሉ እና እዚህ ለማከል አስተማማኝ ላይሆኑ ይችላሉ።"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ገባኝ"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ምግብሮች"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"የ«ምግብሮች» አቋራጭን ለማከል በቅንብሮች ውስጥ «ምግብሮችን በማያ ገፅ ቁልፍ ላይ አሳይ» የሚለው መንቃቱን ያረጋግጡ።"</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ቅንብሮች"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"ማሳወቂያዎች"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ውይይቶች"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ሁሉንም ጸጥ ያሉ ማሳወቂያዎችን ያጽዱ"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ማሳወቂያዎች በአትረብሽ ባሉበት ቆመዋል"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ምንም ማሳወቂያዎች የሉም}=1{ማሳወቂያዎች በ{mode} ባሉበት ቆመዋል}=2{ማሳወቂያዎች በ{mode} እና አንድ ሌላ ሁነታ ባሉበት ቆመዋል}one{ማሳወቂያዎች በ{mode} እና # ሌላ ሁነታ ባሉበት ቆመዋል}other{ማሳወቂያዎች በ{mode} እና # ሌላ ሁነታዎች ባሉበት ቆመዋል}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"አሁን ጀምር"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"የጭንቅላት ክትትል"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"የደዋይ ሁነታን ለመቀየር መታ ያድርጉ"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ደዋይ ሁነታ"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ድምጸ-ከል አድርግ"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ድምጸ-ከልን አንሳ"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ንዘር"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"የቁልፍ ሰሌዳ አቋራጮች"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"የቁልፍ ሰሌዳ አቋራጮችን ያብጁ"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"አቋራጭ ይወገድ?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ወደ ነባሪ ዳግም ይጀመር?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"አቋራጭ ለመመደብ ቁልፍ ይጫኑ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ይህ ብጁ አቋራጭዎን በቋሚነት ይሰርዛል።"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ይህ ሁሉንም ብጁ አቋራጮችዎን በቋሚነት ይሰርዛል።"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"የፍለጋ አቋራጮች"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ምንም የፍለጋ ውጤቶች የሉም"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"መሰብሰቢያ አዶ"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"የቁልፍ ሰሌዳ ቅንብሮች"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"አቋራጭ አቀናብር"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"አስወግድ"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"አዎ፣ ዳግም አስጀምር"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ይቅር"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ቁልፍ ይጫኑ"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"የቁልፍ ጥምረት አስቀድሞ በሥራ ላይ ነው። ሌላ ቁልፍ ይሞክሩ።"</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"በቁልፍ ሰሌዳዎ ላይ ያለውን የተግባር ቁልፍ ይጫኑ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ጥሩ ሠርተዋል!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"የሁሉንም መተግበሪያዎች አሳይ ምልክትን አጠናቅቀዋል"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"የቁልፍ ሰሌዳ የጀርባ ብርሃን"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"ደረጃ %1$d ከ %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"የቤት ውስጥ ቁጥጥሮች"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 4ff613163294..dd6e8500e2a9 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"لفتح تطبيق باستخدام تطبيق مصغَّر، عليك إثبات هويتك. يُرجى ملاحظة أنّ أي شخص يمكنه الاطّلاع محتوى التطبيقات المصغَّرة، حتى وإن كان جهازك اللوحي مُقفلاً. بعض التطبيقات المصغّرة قد لا تكون مُصمَّمة لإضافتها إلى شاشة القفل، وقد يكون هذا الإجراء غير آمن."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"حسنًا"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"التطبيقات المصغَّرة"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"لإضافة اختصار \"التطبيقات المصغّرة\"، يجب تفعيل خيار \"عرض التطبيقات المصغّرة على شاشة القفل\" من خلال الإعدادات."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"الإعدادات"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"الإشعارات"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"المحادثات"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"محو جميع الإشعارات الصامتة"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"تم إيقاف الإشعارات مؤقتًا وفقًا لإعداد \"عدم الإزعاج\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ما مِن إشعارات}=1{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\"}=2{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" ووضع واحد آخر}few{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# أوضاع أخرى}many{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# وضعًا آخر}other{تم إيقاف الإشعارات مؤقتًا بواسطة \"{mode}\" و# وضع آخر}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"البدء الآن"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"تتبُّع حركة الرأس"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"انقر لتغيير وضع الرنين."</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"وضع الرنين"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"كتم الصوت"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"إعادة الصوت"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"اهتزاز"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"اختصارات لوحة المفاتيح"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"تخصيص اختصارات لوحة المفاتيح"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"هل تريد إزالة هذا الاختصار؟"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"يُرجى تأكيد إعادة الضبط على الإعدادات التلقائية"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"اضغط على مفتاح لتخصيص الاختصار"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"سيؤدي هذا الإجراء إلى حذف الاختصار المخصّص نهائيًا."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"سيؤدي هذا الإجراء إلى حذف جميع الاختصارات المخصّصة نهائيًا."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"البحث في الاختصارات"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ما مِن نتائج بحث"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"رمز التصغير"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"إعدادات لوحة المفاتيح"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ضبط الاختصار"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"إزالة"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"نعم، أريد إعادة الضبط"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"إلغاء"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"اضغط على مفتاح"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"يتم حاليًا استخدام مجموعة المفاتيح هذه. يُرجى تجربة مفتاح آخر."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اضغط على مفتاح الإجراء في لوحة المفاتيح"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"أحسنت!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"لقد أكملْت التدريب على إيماءة عرض جميع التطبيقات"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"الإضاءة الخلفية للوحة المفاتيح"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"مستوى الإضاءة: %1$d من %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"إدارة المنزل آليًّا"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index f91a3b011c5d..86e13055960b 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"এটা ৱিজেট ব্যৱহাৰ কৰি কোনো এপ্ খুলিবলৈ, এয়া আপুনিয়েই বুলি সত্যাপন পৰীক্ষা কৰিব লাগিব। লগতে, মনত ৰাখিব যে যিকোনো লোকেই সেইবোৰ চাব পাৰে, আনকি আপোনাৰ টেবলেটটো লক হৈ থাকিলেও। কিছুমান ৱিজেট হয়তো আপোনাৰ লক স্ক্ৰীনৰ বাবে কৰা হোৱা নাই আৰু ইয়াত যোগ কৰাটো অসুৰক্ষিত হ’ব পাৰে।"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"বুজি পালোঁ"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ৱিজেট"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"ৱিজেট\"ৰ শ্বৰ্টকাট যোগ দিবলৈ, ছেটিঙত \"লক স্ক্ৰীনত ৱিজেট দেখুৱাওক\" সক্ষম কৰি থোৱাটো নিশ্চিত কৰক।"</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ছেটিং"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"জাননীসমূহ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"আটাইবোৰ নীৰৱ জাননী মচক"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"অসুবিধা নিদিব-ই জাননী পজ কৰিছে"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{কোনো জাননী নাই}=1{{mode}এ জাননী পজ কৰিছে}=2{{mode} আৰু আন এটা ম’ডে জাননী পজ কৰিছে}one{{mode} আৰু আন # টা ম’ডে জাননী পজ কৰিছে}other{{mode} আৰু আন # টা ম’ডে জাননী পজ কৰিছে}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"এতিয়াই আৰম্ভ কৰক"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"হে’ড ট্ৰেকিং"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ৰিংগাৰ ম’ড সলনি কৰিবলৈ টিপক"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ৰিংগাৰ ম’ড"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট কৰক"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট কৰক"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"কম্পন কৰক"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"কীব’ৰ্ডৰ শ্বৰ্টকাট"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"কীব’ৰ্ডৰ শ্বৰ্টকাট কাষ্টমাইজ কৰক"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"শ্বৰ্টকাট আঁতৰাবনে?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ডিফ\'ল্ট হিচাপে পুনৰ ৰিছেট কৰিবনে?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"শ্বৰ্টকাটৰ ভূমিকা অৰ্পণ কৰিবলৈ কী টিপক"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"এইটোৱে আপোনাৰ কাষ্টম শ্বৰ্টকাট মচিব।"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"এইটোৱে আপোনাৰ আটাইবোৰ কাষ্টম শ্বৰ্টকাট স্থায়ীভাৱে মচিব।"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"সন্ধানৰ শ্বৰ্টকাট"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"সন্ধানৰ কোনো ফলাফল নাই"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"সংকোচন কৰাৰ চিহ্ন"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"কীব’ৰ্ডৰ ছেটিং"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"শ্বৰ্টকাট ছেট কৰক"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"আঁতৰাওক"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"হয়, ৰিছেট কৰক"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"বাতিল কৰক"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"কী টিপক"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"কীৰ মিশ্ৰণ ইতিমধ্যে ব্যৱহাৰ হৈ আছে। অন্য এটা কী ব্যৱহাৰ কৰি চাওক।"</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"বঢ়িয়া!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"আপুনি আটাইবোৰ এপ্ চোৱাৰ নিৰ্দেশনাটো সম্পূৰ্ণ কৰিছে"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীব’ৰ্ডৰ বেকলাইট"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dৰ %1$d স্তৰ"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ঘৰৰ সা-সৰঞ্জামৰ নিয়ন্ত্ৰণ"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 84299dc67ec0..3082284353d3 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirişlər"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Söhbətlər"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Səssiz bildirişlərin hamısını silin"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirişlər \"Narahat Etməyin\" rejimi tərəfindən dayandırıldı"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Bildiriş yoxdur}=1{Bildirişlər {mode} tərəfindən dayandırıldı}=2{Bildirişlər {mode} və digər rejim tərəfindən dayandırıldı}other{Bildirişlər {mode} və # digər rejim tərəfindən dayandırıldı}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"İndi başlayın"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Baş izləməsi"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Zəng rejimini dəyişmək üçün toxunun"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"zəng səsi rejimi"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"susdurun"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"səssiz rejimdən çıxarın"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrasiya"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klaviaturada fəaliyyət açarına basın"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Əla!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"\"Bütün tətbiqlərə baxın\" jestini tamamladınız"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura işığı"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Səviyyə %1$d/%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Ev nizamlayıcıları"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index bc385a10160f..09aef06b942a 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Vidžeti"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Da biste dodali prečicu Vidžeti, uverite se da je u podešavanjima omogućeno Prikazuj vidžete na zaključanom ekranu."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Podešavanja"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obaveštenja"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzacije"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Obrišite sva nečujna obaveštenja"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Obaveštenja su pauzirana režimom Ne uznemiravaj"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nema obaveštenja}=1{Obaveštenja je pauzirao {mode}}=2{Obaveštenja su pauzirali {mode} i još jedan režim}one{Obaveštenja su pauzirali {mode} i još # režim}few{Obaveštenja su pauzirali {mode} i još # režima}other{Obaveštenja su pauzirali {mode} i još # režima}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Započni"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Praćenje glave"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da biste promenili režim zvona"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"režim zvona"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibracija"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Tasterske prečice"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodite tasterske prečice"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite da uklonite prečicu?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite da resetujete na podrazumevano?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite taster da biste dodelili prečicu"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ovim ćete trajno izbrisati prilagođenu prečicu."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Time ćete trajno izbrisati sve prilagođene prečice."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pretražite prečice"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretrage"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za skupljanje"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Podešavanja tastature"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Podesi prečicu"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Ukloni"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Da, resetuj"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Otkaži"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite taster"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinacija tastera se već koristi. Probajte sa drugim tasterom."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite taster radnji na tastaturi"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Dovršili ste pokret za prikazivanje svih aplikacija."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvetljenje tastature"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index a5f4da95a892..51cc35a070ce 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Каб адкрыць праграму з дапамогай віджэта, вам неабходна будзе пацвердзіць сваю асобу. Таксама памятайце, што такія віджэты могуць пабачыць іншыя людзі, нават калі экран планшэта заблакіраваны. Некаторыя віджэты могуць не падыходзіць для выкарыстання на экране блакіроўкі, і дадаваць іх сюды можа быць небяспечна."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Зразумела"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Віджэты"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Каб дадаць спалучэнне клавіш \"Віджэты\", у наладах павінна быць уключана функцыя \"Паказваць віджэты на экране блакіроўкі\"."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Налады"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Апавяшчэнні"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Размовы"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Выдаліць усе апавяшчэнні без гуку"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Паказ апавяшчэнняў прыпынены ў рэжыме \"Не турбаваць\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Апавяшчэнняў няма}=1{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\"}=2{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ адным рэжымам}one{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ # рэжымам}few{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ # рэжымамі}many{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ # рэжымамі}other{Атрыманне апавяшчэнняў прыпынена рэжымам \"{mode}\" і яшчэ # рэжыму}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Пачаць зараз"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Адсочваць рух галавы"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Націсніце, каб змяніць рэжым званка"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"рэжым званка"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"выключыць гук"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"уключыць гук"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вібрыраваць"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Спалучэнні клавіш"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Наладзіць спалучэнні клавіш"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Выдаліць спалучэнне клавіш?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Скінуць налады да стандартных?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Націсніце клавішу, каб прызначыць спалучэнне клавіш"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Гэта дзеянне назаўсёды выдаліць прызначанае вамі спалучэнне клавіш."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Усе карыстальніцкія спалучэнні клавіш будуць назаўсёды выдалены."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Пошук спалучэнняў клавіш"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Няма вынікаў пошуку"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Згарнуць\""</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Налады клавіятуры"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Наладзіць спалучэнне клавіш"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Выдаліць"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Так, скінуць"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Скасаваць"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Націсніце клавішу"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Гэта спалучэнне клавіш ужо выкарыстоўваецца. Паспрабуйце іншую клавішу."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Націсніце клавішу дзеяння на клавіятуры"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Выдатна!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Вы навучыліся рабіць жэст для прагляду ўсіх праграм"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Падсветка клавіятуры"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Узровень %1$d з %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Кіраванне домам"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index e36cf3098117..12e25cca0c1b 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Известия"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Изчистване на всички беззвучни известия"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известията са поставени на пауза от режима „Не безпокойте“"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Няма известия}=1{Известията са поставени на пауза от {mode}}=2{Известията са поставени на пауза от {mode} и един друг режим}other{Известията са поставени на пауза от {mode} и # други режима}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Стартиране сега"</string> @@ -707,6 +709,7 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Прослед. на движенията на главата"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Докоснете, за да промените режима на звънене"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"режим на звънене"</string> + <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>: докоснете, за да промените режима на звънене"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"спиране"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"пускане"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибриране"</string> @@ -1482,6 +1485,7 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Натиснете клавиша за действия на клавиатурата си"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Браво!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Изпълнихте жеста за преглед на всички приложения"</string> + <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Анимация за урока. Кликнете, за да поставите на пауза и да възобновите възпроизвеждането."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка на клавиатурата"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d от %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Контроли за дома"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 8f5effc01982..8af32a83a35f 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"বিজ্ঞপ্তি"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"কথোপকথন"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"সব নীরব বিজ্ঞপ্তি মুছুন"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'বিরক্ত করবে না\' দিয়ে বিজ্ঞপ্তি পজ করা হয়েছে"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{কোনও বিজ্ঞপ্তি নেই}=1{{mode}-এর জন্য বিজ্ঞপ্তি পজ করা হয়েছে}=2{{mode} ও অন্য আরেকটি মোডের জন্য বিজ্ঞপ্তি পজ করা হয়েছে}one{{mode} ও অন্য #টি মোডের জন্য বিজ্ঞপ্তি পজ করা হয়েছে}other{{mode} ও অন্য #টি মোডের জন্য বিজ্ঞপ্তি পজ করা হয়েছে}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"এখন শুরু করুন"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"হেড ট্র্যাকিং"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"রিঙ্গার মোড পরিবর্তন করতে ট্যাপ করুন"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"রিঙ্গার মোড"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"মিউট করুন"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"আনমিউট করুন"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ভাইব্রেট করান"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"আপনার কীবোর্ডে অ্যাকশন কী প্রেস করুন"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"দারুণ!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"আপনি \'সব অ্যাপের জেসচার দেখুন\' টিউটোরিয়াল সম্পূর্ণ করেছেন"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"কীবোর্ড ব্যাকলাইট"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-এর মধ্যে %1$d লেভেল"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"হোম কন্ট্রোল"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 0a88d447b202..fe38ba846a18 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Vidžeti"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Da biste dodali prečac Widgeti, provjerite je li u postavkama omogućena opcija Prikaži widgete na zaključanom zaslonu."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Postavke"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavještenja"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Obriši sva nečujna obavještenja"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Obavještenja su pauzirana načinom rada Ne ometaj"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nema obavještenja}=1{Obavještenja su pauzirana putem načina rada {mode}}=2{Obavještenja su pauzirana putem načina rada {mode} i još jednog načina rada}one{Obavještenja su pauzirana putem načina rada {mode} i još # načina rada}few{Obavještenja su pauzirana putem načina rada {mode} i još # načina rada}other{Obavještenja su pauzirana putem načina rada {mode} i još # načina rada}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Započni odmah"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Praćenje položaja glave"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da promijenite način rada zvuka zvona"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"način rada za zvuk zvona"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključite zvuk"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključite zvuk"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Prečice tastature"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodite prečice na tastaturi"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Ukloniti prečicu?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite li vratiti na zadano?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipku da dodijelite prečicu"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ovo će trajno izbrisati prilagođenu prečicu."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Time će se trajno izbrisati svi vaši prilagođeni prečaci."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečica pretraživanja"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona sužavanja"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Postavke tastature"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Postavi prečicu"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Ukloni"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Da, vrati na zadano"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Otkaži"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipku"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ta se kombinacija tipki već koristi. Pokušajte s drugom tipkom."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku radnji na tastaturi"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Izvršili ste pokret za prikaz svih aplikacija"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tastature"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. nivo od %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrole za dom"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 614fe233c965..ba3c4adccb42 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Per afegir la drecera Widgets, assegura\'t que l\'opció Mostra els widgets a la pantalla de bloqueig estigui activada a la configuració."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Configuració"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificacions"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Converses"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Esborra totes les notificacions silencioses"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificacions pausades pel mode No molestis"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No hi ha cap notificació}=1{{mode} ha posat en pausa les notificacions}=2{{mode} i un altre mode han posat en pausa les notificacions}many{{mode} i # de modes més han posat en pausa les notificacions}other{{mode} i # modes més han posat en pausa les notificacions}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Comença ara"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Seguiment del cap"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Toca per canviar el mode de timbre"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"mode de timbre"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"deixar de silenciar"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Tecles de drecera"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalitza les tecles de drecera"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Vols suprimir la drecera?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vols restablir els valors predeterminats?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Prem la tecla per assignar la drecera"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Aquesta acció suprimirà la drecera personalitzada permanentment."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Aquesta acció suprimirà totes les dreceres personalitzades permanentment."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Dreceres de cerca"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No hi ha cap resultat de la cerca"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Replega la icona"</string> @@ -1449,8 +1449,7 @@ <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_remove_button_label" msgid="6546386970440176552">"Suprimeix"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <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> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Prem una tecla"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinació de tecles ja s\'està utilitzant. Prova-ho amb una altra tecla."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Prem la tecla d\'acció al teclat"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Enhorabona!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Has completat el gest per veure totes les aplicacions"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroil·luminació del teclat"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivell %1$d de %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Controls de la llar"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 9d5a97a34bde..317061f07edf 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Oznámení"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzace"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazat všechna tichá oznámení"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Oznámení jsou pozastavena režimem Nerušit"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Žádná oznámení}=1{Oznámení jsou pozastavená režimem {mode}}=2{Oznámení jsou pozastavená režimem {mode} a 1 dalším}few{Oznámení jsou pozastavená režimem {mode} a # dalšími}many{Oznámení jsou pozastavená režimem {mode} a # dalšího}other{Oznámení jsou pozastavená režimem {mode} a # dalšími}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Spustit"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Sledování hlavy"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Klepnutím změníte režim vyzvánění"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"režim vyzvánění"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnout zvuk"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnout zvuk"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrovat"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stiskněte akční klávesu na klávesnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Výborně!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Provedli jste gesto k zobrazení všech aplikací"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvícení klávesnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Úroveň %1$d z %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládání domácnosti"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 53f34620c267..3c0dc42c0b05 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikationer"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ryd alle lydløse notifikationer"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifikationer er sat på pause af Forstyr ikke"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ingen notifikationer}=1{Notifikationer er sat på pause af {mode}}=2{Notifikationer er sat på pause af {mode} og én anden tilstand}one{Notifikationer er sat på pause af {mode} og # anden tilstand}other{Notifikationer er sat på pause af {mode} og # andre tilstande}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Start nu"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Hovedregistrering"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tryk for at ændre ringetilstand"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ringetilstand"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"slå lyden fra"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå lyden til"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tryk på handlingstasten på dit tastatur"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Flot klaret!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du har udført bevægelsen for at se alle apps"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturets baggrundslys"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d af %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Hjemmestyring"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index e40445af0dbe..8d13524c951f 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Benachrichtigungen"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Unterhaltungen"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle lautlosen Benachrichtigungen löschen"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Benachrichtigungen durch „Bitte nicht stören“ pausiert"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Keine Benachrichtigungen}=1{Benachrichtigungen durch {mode} pausiert}=2{Benachrichtigungen durch {mode} und einen weiteren Modus pausiert}other{Benachrichtigungen durch {mode} und # weitere Modi pausiert}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Jetzt starten"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Erfassung von Kopfbewegungen"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Zum Ändern des Klingeltonmodus tippen"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"Klingeltonmodus"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"Stummschalten"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"Aufheben der Stummschaltung"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"Vibrieren lassen"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Drücke die Aktionstaste auf deiner Tastatur"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Perfekt!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du hast das Tutorial für die Touch-Geste zum Aufrufen aller Apps abgeschlossen"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastaturbeleuchtung"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d von %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Smart-Home-Steuerung"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 43fa01a1e653..b6de5393087d 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ειδοποιήσεις"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Συζητήσεις"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Διαγραφή όλων των ειδοποιήσεων σε σίγαση"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία \"Μην ενοχλείτε\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Δεν υπάρχουν ειδοποιήσεις}=1{Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία {mode}}=2{Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία {mode} και μία άλλη λειτουργία}other{Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία {mode} και # άλλες λειτουργίες}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Έναρξη τώρα"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Παρακ. κίνησ. κεφαλής"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Πατήστε για να αλλάξετε τη λειτουργία ειδοποίησης ήχου"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"λειτουργία ειδοποίησης ήχου"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"σίγαση"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"κατάργηση σίγασης"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"δόνηση"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Πατήστε το πλήκτρο ενέργειας στο πληκτρολόγιό σας"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Μπράβο!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Ολοκληρώσατε την κίνηση για την προβολή όλων των εφαρμογών"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Οπίσθιος φωτισμός πληκτρολογίου"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Επίπεδο %1$d από %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Οικιακοί έλεγχοι"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index d32c95acc5e6..609e7afc2109 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No notifications}=1{Notifications paused by {mode}}=2{Notifications paused by {mode} and one other mode}other{Notifications paused by {mode} and # other modes}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Head tracking"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ringer mode"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 8a7420d9dd96..be4e81fd1fb7 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -591,6 +591,7 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string> + <string name="accessibility_notification_section_header_open_settings" msgid="6235202417954844004">"Open notifications settings"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No notifications}=1{Notifications paused by {mode}}=2{Notifications paused by {mode} and one other mode}other{Notifications paused by {mode} and # other modes}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string> @@ -705,6 +706,7 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Head Tracking"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ringer mode"</string> + <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>, tap to change ringer mode"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string> @@ -1434,8 +1436,7 @@ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Action or Meta key icon"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plus icon"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Customize"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Reset"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Done"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Expand icon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"or"</string> @@ -1477,6 +1478,7 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string> + <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Tutorial animation, click to pause and resume play."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Home Controls"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index d32c95acc5e6..609e7afc2109 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No notifications}=1{Notifications paused by {mode}}=2{Notifications paused by {mode} and one other mode}other{Notifications paused by {mode} and # other modes}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Head tracking"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ringer mode"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index d32c95acc5e6..609e7afc2109 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No notifications}=1{Notifications paused by {mode}}=2{Notifications paused by {mode} and one other mode}other{Notifications paused by {mode} and # other modes}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Start now"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Head tracking"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tap to change ringer mode"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ringer mode"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mute"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"unmute"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrate"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Press the action key on your keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Well done!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"You completed the view all apps gesture"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Keyboard backlight"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d of %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Home controls"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 711f771842e2..177e6900e351 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciosas"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo \"No interrumpir\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No hay notificaciones}=1{{mode} pausó las notificaciones}=2{{mode} y un modo más pausaron las notificaciones}many{{mode} y # de modos más pausaron las notificaciones}other{{mode} y # modos más pausaron las notificaciones}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Comenzar ahora"</string> @@ -707,6 +709,7 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Monitoreo de cabeza"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Presiona para cambiar el modo de timbre"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modo de timbre"</string> + <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>, presiona para cambiar el modo de timbre"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string> @@ -1482,6 +1485,7 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Presiona la tecla de acción en el teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"¡Bien hecho!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Completaste el gesto para ver todas las apps"</string> + <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animación del instructivo. Haz clic para pausar y reanudar la reproducción."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Controles de la casa"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 4a94cdfd0852..53289d141b0e 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -306,7 +306,7 @@ <string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectado"</string> <string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Compartir audio"</string> - <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="8680997711431098238">"Permite compartir audio"</string> + <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="8680997711431098238">"Admite Compartir audio"</string> <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Guardado"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"activar"</string> @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para añadir el acceso directo Widgets, asegúrate de que la opción Mostrar widgets en la pantalla de bloqueo esté habilitada en los ajustes."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Ajustes"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciosas"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo No molestar"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{No hay notificaciones}=1{Notificaciones pausadas por {mode}}=2{Notificaciones pausadas por {mode} y un modo más}many{Notificaciones pausadas por {mode} y # modos más}other{Notificaciones pausadas por {mode} y # modos más}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Empezar ahora"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Seguimiento de cabeza"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Toca para cambiar el modo de timbre"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modo de timbre"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Combinaciones de teclas"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizar las combinaciones de teclas"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"¿Eliminar combinación de teclas?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"¿Restablecer valores predeterminados?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pulsa una tecla para asignar una combinación de teclas"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Se eliminará tu combinación de teclas personalizada de forma permanente."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Se eliminarán todos tus accesos directos personalizados de forma permanente."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Atajos de búsqueda"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"No hay resultados de búsqueda"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icono de contraer"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ajustes del teclado"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Establecer combinación de teclas"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Eliminar"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sí, restablecer"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pulsa una tecla"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"La combinación de teclas ya se está usando. Prueba con otra tecla."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pulsa la tecla de acción de tu teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"¡Muy bien!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Has completado el gesto para ver todas las aplicaciones"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación del teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Controles de la casa"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 4027bbdd9ca1..165f9c25c2b1 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Märguanded"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Vestlused"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Kustuta kõik hääletud märguanded"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Režiim Mitte segada peatas märguanded"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Märguandeid pole}=1{{mode} peatas märguanded}=2{{mode} ja veel üks režiim peatasid märguanded}other{{mode} ja veel # režiimi peatasid märguanded}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Alusta kohe"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Pea jälgimine"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Puudutage telefonihelina režiimi muutmiseks"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"telefonihelina režiim"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vaigistamine"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vaigistuse tühistamine"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibreerimine"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Vajutage klaviatuuril toiminguklahvi"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hästi tehtud!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Tegite kõigi rakenduste vaatamise liigutuse"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatuuri taustavalgustus"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tase %1$d/%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kodu juhtelemendid"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index a0ba1b78a081..46bbdc3dd3c0 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Jakinarazpenak"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Elkarrizketak"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Garbitu soinurik gabeko jakinarazpen guztiak"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ez molestatzeko moduak pausatu egin ditu jakinarazpenak"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ez dago jakinarazpenik}=1{Modu honek jakinarazpenak pausatu ditu: {mode}}=2{Modu honek eta beste modu batek jakinarazpenak pausatu dituzte: {mode}}other{Modu honek eta beste # moduk jakinarazpenak pausatu dituzte: {mode}}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Hasi"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Buruaren jarraipena"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Sakatu tonu-jotzailearen modua aldatzeko"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"tonu-jotzailearen modua"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desaktibatu audioa"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktibatu audioa"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dardara"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Sakatu teklatuko ekintza-tekla"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bikain!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Osatu duzu aplikazio guztiak ikusteko keinua"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Teklatuaren hondoko argia"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d/%2$d maila"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Etxeko gailuen kontrola"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 7bd01bc1a322..5e68a95cbecb 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"اعلانها"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"مکالمهها"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"پاک کردن همه اعلانهای بیصدا"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"اعلانها توسط «مزاحم نشوید» موقتاً متوقف شدند"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{اعلانی موقتاً متوقف نشده است}=1{اعلانها را «{mode}» موقتاً متوقف کرده است}=2{اعلانها را «{mode}» و یک حالت دیگر موقتاً متوقف کرداند}one{اعلانها را «{mode}» و # حالت دیگر موقتاً متوقف کردهاند}other{اعلانها را «{mode}» و # حالت دیگر موقتاً متوقف کردهاند}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"اکنون شروع کنید"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ردیابی سر"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"برای تغییر حالت زنگ، تکضرب بزنید"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"حالت زنگ"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"صامت کردن"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"باصدا کردن"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"لرزش"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"دکمه کنش را روی صفحه لمسی فشار دهید"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"عالی بود!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"اشاره «مشاهده همه برنامهها» را تمام کردید"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"نور پسزمینه صفحهکلید"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"سطح %1$d از %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"کنترل خانه هوشمند"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index e6174515c8d4..94b63649349c 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgetit"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Jos haluat lisätä Widgetit-pikakuvakkeen, varmista, että \"Näytä widgetit lukitusnäytöllä\" on käytössä asetuksissa."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Asetukset"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ilmoitukset"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Keskustelut"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Tyhjennä kaikki hiljaiset ilmoitukset"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Älä häiritse ‑tila keskeytti ilmoitukset"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ei ilmoituksia}=1{{mode} keskeytti ilmoitukset}=2{{mode} ja yksi muu tila keskeytti ilmoitukset}other{{mode} ja # muuta tilaa keskeytti ilmoitukset}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Aloita nyt"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Pään seuranta"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Vaihda soittoäänen tilaa napauttamalla"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"Soittoäänen tila"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"mykistä"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"poista mykistys"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"värinä"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Pikanäppäimet"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Pikanäppäimien muokkaaminen"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Poistetaanko pikanäppäin?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Palautetaanko oletusasetukset?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Määritä pikanäppäin painamalla näppäintä"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Oma pikanäppäin poistetaan pysyvästi."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Kaikki omat pikanäppäimet poistetaan pysyvästi."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pikahaut"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ei hakutuloksia"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Tiivistyskuvake"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Näppäimistön asetukset"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Valitse pikanäppäin"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Poista"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Kyllä, nollaa"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Peru"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Paina näppäintä"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Näppäinyhdistelmä on jo käytössä. Kokeile toista näppäintä."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Paina näppäimistön toimintonäppäintä"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Hienoa!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Olet oppinut Näytä kaikki sovellukset ‑eleen."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Näppämistön taustavalo"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Taso %1$d/%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kodin ohjaus"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 6213dd581b57..ea9ee0b42c2d 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Effacer toutes les notifications silencieuses"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Les notifications sont suspendues par le mode Ne pas déranger"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Aucune notification}=1{Notifications suspendues par {mode}}=2{Notifications suspendues par {mode} et un autre mode}one{Notifications suspendues par {mode} et # autre mode}many{Notifications suspendues par {mode} et # d\'autres modes}other{Notifications suspendues par {mode} et # autres modes}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Commencer"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Suivi de la tête"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Touchez pour modifier le mode de sonnerie"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"mode de sonnerie"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"désactiver le son"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Appuyez sur la touche d\'action de votre clavier"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Félicitations!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Vous avez appris le geste pour afficher toutes les applis"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d de %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Domotique"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index d0931a687947..bda70d970e13 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Effacer toutes les notifications silencieuses"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications suspendues par le mode Ne pas déranger"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Aucune notification}=1{Notifications suspendues par le mode {mode}}=2{Notifications suspendues par le mode {mode} et un autre mode}one{Notifications suspendues par le mode {mode} et # autre mode}many{Notifications suspendues par le mode {mode} et # d\'autres modes}other{Notifications suspendues par le mode {mode} et # autres modes}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Commencer"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Suivi de la tête"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Appuyez pour changer le mode de la sonnerie"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"mode de sonnerie"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"couper le son"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"réactiver le son"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"activer le vibreur"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Appuyez sur la touche d\'action de votre clavier"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bravo !"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Vous avez appris le geste pour afficher toutes les applis"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Rétroéclairage du clavier"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d sur %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Contrôle de la maison"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index a02206ddc1a5..53c4417b3305 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificacións"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas as notificacións silenciadas"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"O modo Non molestar puxo en pausa as notificacións"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Non hai ningunha notificación}=1{Notificacións postas en pausa polo modo {mode}}=2{Notificacións postas en pausa polo modo {mode} e un máis}other{Notificacións postas en pausa polo modo {mode} e # máis}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Seguimento da cabeza"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Toca para cambiar o modo de timbre"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modo de timbre"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activar o son"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Preme a tecla de acción do teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Ben feito!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Completaches o titorial do xesto de ver todas as aplicacións"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroiluminación do teclado"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivel %1$d de %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Controis domóticos"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 8cff7ff01eca..8ff57172babb 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"વિજેટનો ઉપયોગ કરીને ઍપ ખોલવા માટે, તમારે એ ચકાસણી કરવાની જરૂર રહેશે કે આ તમે જ છો. તે ઉપરાંત, ધ્યાનમાં રાખો કે તમારું ટૅબ્લેટ લૉક કરેલું હોય તો પણ કોઈપણ વ્યક્તિ તેમને જોઈ શકે છે. અમુક વિજેટ કદાચ તમારી લૉક સ્ક્રીન માટે બનાવવામાં આવ્યા ન હોઈ શકે છે અને તેમને અહીં ઉમેરવાનું અસલામત હોઈ શકે છે."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"સમજાઈ ગયું"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"વિજેટ"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"વિજેટ\"નો શૉર્ટકટ ઉમેરવા માટે, ખાતરી કરો કે સેટિંગમાં \"લૉક સ્ક્રીન પર વિજેટ બતાવો\" સુવિધા ચાલુ કરેલી છે."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"સેટિંગ"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"નોટિફિકેશન"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"વાતચીત"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"બધા સાઇલન્ટ નોટિફિકેશન સાફ કરો"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ખલેલ પાડશો નહીં દ્વારા થોભાવેલ નોટિફિકેશન"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{કોઈ નોટિફિકેશન નથી}=1{{mode} દ્વારા નોટિફિકેશન થોભાવવામાં આવ્યા}=2{{mode} અને અન્ય એક મોડ દ્વારા નોટિફિકેશન થોભાવવામાં આવ્યા}one{{mode} અને અન્ય # મોડ દ્વારા નોટિફિકેશન થોભાવવામાં આવ્યા}other{{mode} અને અન્ય # મોડ દ્વારા નોટિફિકેશન થોભાવવામાં આવ્યા}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"હવે શરૂ કરો"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"હૅડ ટ્રૅકિંગ"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"રિંગર મોડ બદલવા માટે ટૅપ કરો"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"રિંગર મોડ"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"મ્યૂટ કરો"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"અનમ્યૂટ કરો"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"વાઇબ્રેટ"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"કીબોર્ડ શૉર્ટકટ"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"કીબોર્ડ શૉર્ટકટને કસ્ટમાઇઝ કરો"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"શું શૉર્ટકટ કાઢી નાખીએ?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"પાછા ડિફૉલ્ટ પર રીસેટ કરીએ?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"શૉર્ટકટ સોંપવા માટે કી દબાવો"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"આ તમારા કસ્ટમ શૉર્ટકટને કાયમી રીતે ડિલીટ કરશે."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"આ તમારા બધા કસ્ટમ શૉર્ટકટને કાયમ માટે ડિલીટ કરશે."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"શૉર્ટકટ શોધો"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"કોઈ શોધ પરિણામો નથી"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"\'નાનું કરો\'નું આઇકન"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"કીબોર્ડના સેટિંગ"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"શૉર્ટકટ સેટ કરો"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"કાઢી નાખો"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"હા, રીસેટ કરો"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"રદ કરો"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"કી દબાવો"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"કી સંયોજન પેહલેથી ઉપયોગમાં છે. અન્ય કી અજમાવી જુઓ."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"તમારા કીબોર્ડ પરની ઍક્શન કી દબાવો"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"વાહ!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"તમે \'બધી ઍપ જુઓ\' સંકેત પૂર્ણ કર્યો"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"કીબોર્ડની બૅકલાઇટ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dમાંથી %1$d લેવલ"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ઘરેલું સાધનોના નિયંત્રણો"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 474014ce3cea..d2f6e5a1d68d 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचनाएं"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"बातचीत"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"बिना आवाज़ की सभी सूचनाएं हटाएं"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'परेशान न करें\' सुविधा के ज़रिए कुछ समय के लिए सूचनाएं दिखाना रोक दिया गया है"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{कोई सूचना नहीं है}=1{{mode} की वजह से सूचना नहीं दिख रही है}=2{{mode} और एक अन्य मोड की वजह से सूचना नहीं दिख रही है}one{{mode} और # अन्य मोड की वजह से सूचना नहीं दिख रही है}other{{mode} और # अन्य मोड के की वजह से सूचनाएं नहीं दिख रही है}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"अभी शुरू करें"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"हेड ट्रैकिंग चालू है"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"रिंगर मोड बदलने के लिए टैप करें"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"रिंगर मोड"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करें"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्यूट करें"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"वाइब्रेशन की सुविधा चालू करें"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"अपने कीबोर्ड पर ऐक्शन बटन दबाएं"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"बहुत खूब!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"अब आपको हाथ के जेस्चर का इस्तेमाल करके, सभी ऐप्लिकेशन देखने का तरीका पता चल गया है"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड की बैकलाइट"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d में से %1$d लेवल"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 35996ea1c1c9..e566e4ef12c2 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgeti"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Da biste dodali prečac Widgeti, provjerite je li u postavkama omogućena opcija Prikaži widgete na zaključanom zaslonu."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Postavke"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući izbornik"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Izbrisat će se sve aplikacije i podaci u ovoj sesiji."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavijesti"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Izbriši sve bešumne obavijesti"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Značajka Ne uznemiravaj pauzirala je Obavijesti"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nema obavijesti}=1{Obavijesti je pauzirao način {mode}}=2{Obavijesti su pauzirali način {mode} i još jedan način}one{Obavijesti su pauzirali način {mode} i još # način rada}few{Obavijesti su pauzirali način {mode} i još # načina rada}other{Obavijesti su pauzirali način {mode} i još # načina rada}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Pokreni"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Praćenje glave"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Dodirnite da biste promijenili način softvera zvona"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"način softvera zvona"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"isključivanje zvuka"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"uključivanje zvuka"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string> @@ -859,7 +861,7 @@ <string name="keyboard_shortcut_a11y_filter_current_app" msgid="7944592357493737911">"Prikazuju se prečaci za trenutačnu aplikaciju"</string> <string name="group_system_access_notification_shade" msgid="1619028907006553677">"Prikaz obavijesti"</string> <string name="group_system_full_screenshot" msgid="5742204844232667785">"Snimanje zaslona"</string> - <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Prikaži prečace"</string> + <string name="group_system_access_system_app_shortcuts" msgid="8562482996626694026">"Prikaz prečaca"</string> <string name="group_system_go_back" msgid="2730322046244918816">"Natrag"</string> <string name="group_system_access_home_screen" msgid="4130366993484706483">"Otvaranje početnog zaslona"</string> <string name="group_system_overview_open_apps" msgid="5659958952937994104">"Prikaz nedavnih aplikacija"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Tipkovni prečaci"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagodba tipkovnih prečaca"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite li ukloniti prečac?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite li vratiti na zadano?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipku da biste dodijelili prečac"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Time će se vaš prilagođeni prečac trajno izbrisati."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Time će se trajno izbrisati svi vaši prilagođeni prečaci."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prečaci za pretraživanje"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nema rezultata pretraživanja"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za sažimanje"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Postavke tipkovnice"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Postavite prečac"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Ukloni"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Da, vrati na zadano"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Odustani"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipku"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinacija tipki već se upotrebljava. Pokušajte s drugom tipkom."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipku za radnju na tipkovnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Izvrsno!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Napravili ste pokret za prikaz svih aplikacija"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Pozadinsko osvjetljenje tipkovnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Razina %1$d od %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Upravljanje uređajima"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index c807aee30bb1..0cbf0aac77f6 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Értesítések"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Beszélgetések"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Az összes néma értesítés törlése"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ne zavarjanak funkcióval szüneteltetett értesítések"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nincs értesítés}=1{A(z) {mode} szüneteltette az értesítéseket}=2{A(z) {mode} és egy másik mód szüneteltette az értesítéseket}other{A(z) {mode} és # másik mód szüneteltette az értesítéseket}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Indítás most"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Fejkövetés"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Koppintson a csengés módjának módosításához"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"csengés módja"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"némítás"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"némítás feloldása"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rezgés"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Nyomja meg a műveletbillentyűt az érintőpadon."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Szép munka!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Teljesítette az összes alkalmazás megtekintésének kézmozdulatát."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"A billentyűzet háttérvilágítása"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Fényerő: %2$d/%1$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Otthon vezérlése"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 5603aff7f059..867e0dafbdec 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ծանուցումներ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Զրույցներ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ջնջել բոլոր անձայն ծանուցումները"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ծանուցումները չեն ցուցադրվի «Չանհանգստացնել» ռեժիմում"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ծանուցումներ չկան}=1{Ծանուցումները դադարեցվել են «{mode}» ռեժիմի կողմից}=2{Ծանուցումները դադարեցվել են «{mode}» ու ևս մի ռեժիմի կողմից}one{Ծանուցումները դադարեցվել են «{mode}» ու ևս # ռեժիմի կողմից}other{Ծանուցումները դադարեցվել են «{mode}» ու ևս # ռեժիմի կողմից}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Սկսել հիմա"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Գլխի շարժումների հետագծում"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Հպեք՝ զանգակի ռեժիմը փոխելու համար"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"զանգակի ռեժիմ"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"անջատել ձայնը"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"միացնել ձայնը"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"միացնել թրթռոցը"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Սեղմեք գործողության ստեղնը ստեղնաշարի վրա"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Հիանալի՛ է"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Դուք սովորեցիք բոլոր հավելվածները դիտելու ժեստը"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Հետին լուսավորությամբ ստեղնաշար"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d՝ %2$d-ից"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Տան կառավարման տարրեր"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 3820ab749854..06ecd11b67e9 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikasi"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Percakapan"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Hapus semua notifikasi senyap"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifikasi dijeda oleh mode Jangan Ganggu"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Tidak ada notifikasi}=1{Notifikasi dijeda oleh {mode}}=2{Notifikasi dijeda oleh {mode} dan satu mode lainnya}other{Notifikasi dijeda oleh {mode} dan # mode lainnya}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Mulai sekarang"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Pelacakan Gerak Kepala"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Ketuk untuk mengubah mode pendering"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"mode pendering"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"Tanpa suara"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktifkan"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan tombol tindakan di keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Oke!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Anda telah menyelesaikan gestur untuk melihat semua aplikasi"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Lampu latar keyboard"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tingkat %1$d dari %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrol Rumah"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 931c3dc172a3..4f6ff47a35c7 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Græjur"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Gakktu úr skugga um að kveikt sé á „Sýna græjur á lásskjá“ til að geta bætt flýtileiðinni „Græjur“ við."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Stillingar"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Fellivalmynd"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Tilkynningar"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtöl"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Hreinsa allar þöglar tilkynningar"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Hlé gert á tilkynningum þar sem stillt er á „Ónáðið ekki“"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Engar tilkynningar}=1{Hlé gert á tilkynningum þar sem stillt er á {mode}}=2{Hlé gert á tilkynningum þar sem stillt er á {mode} og eina aðra stillingu}one{Hlé gert á tilkynningum þar sem stillt er á {mode} og # aðra stillingu}other{Hlé gert á tilkynningum þar sem stillt er á {mode} og # aðrar stillingar}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Byrja núna"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Rakning höfuðhreyfinga"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Ýta til að skipta um hringjarastillingu"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"hringistilling"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"þagga"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"hætta að þagga"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titringur"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Flýtilyklar"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sérsníddu flýtilykla"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Fjarlægja flýtileið?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Endurstilla á sjálfgefið?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Ýttu á lykil til að stilla flýtileið"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Þetta eyðir sérsniðnu flýtileiðinni varanlega."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Þetta verður til þess að öllum sérsniðnu flýtileiðunum þínum verður eytt varanlega."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Leita að flýtileiðum"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Engar leitarniðurstöður"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Minnka tákn"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Stillingar lyklaborðs"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Stilltu flýtileið"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Fjarlægja"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Já, endurstilla"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Hætta við"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Ýttu á lykil"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Lyklasamsetningin er þegar í notkun. Prófaðu annan lykil."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Ýttu á aðgerðalykilinn á lyklaborðinu"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Vel gert!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Þú framkvæmdir bendinguna „Sjá öll forrit“"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Baklýsing lyklaborðs"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Stig %1$d af %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Heimastýringar"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 7c2fc4f5a0ed..76e3360bf88a 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widget"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Per aggiungere la scorciatoia \"Widget\", assicurati che l\'opzione \"Mostra widget sulla schermata di blocco\" sia abilitata nelle impostazioni."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Impostazioni"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambio utente"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu a discesa"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifiche"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversazioni"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Cancella tutte le notifiche silenziose"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifiche messe in pausa in base alla modalità Non disturbare"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nessuna notifica}=1{Notifica messa in pausa da {mode}}=2{Notifiche messe in pausa da {mode} e un\'altra modalità}many{Notifiche messe in pausa da {mode} e # di modalità}other{Notifiche messe in pausa da {mode} e altre # modalità}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Avvia adesso"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Rilev. movim. testa"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tocca per cambiare la modalità della suoneria"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modalità suoneria"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenzia"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"riattiva l\'audio"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrazione"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Scorciatoie da tastiera"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalizza scorciatoie da tastiera"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Rimuovere scorciatoia?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Vuoi ripristinare il valore predefinito?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Premi un tasto per assegnare una scorciatoia"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"La scorciatoia personalizzata verrà eliminata definitivamente."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Tutte le tue scorciatoie personalizzate verranno eliminate definitivamente."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Scorciatoie per la ricerca"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nessun risultato di ricerca"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icona Comprimi"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Impostazioni tastiera"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Imposta scorciatoia"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Rimuovi"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sì, ripristina"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annulla"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Premi un tasto"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Combinazione di tasti già in uso. Prova con un altro tasto."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Premi il tasto azione sulla tastiera"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Ben fatto!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Hai completato il gesto Visualizza tutte le app."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Retroilluminazione della tastiera"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Livello %1$d di %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Controlli della casa"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index e481a777c15a..3257e14bd933 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"התראות"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"שיחות"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ניקוי כל ההתראות השקטות"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"התראות הושהו על ידי מצב \'נא לא להפריע\'"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{אין התראות}=1{ההתראות הושהו על ידי {mode}}=2{ההתראות הושהו על ידי {mode} ועל ידי מצב אחד נוסף}one{ההתראות הושהו על ידי {mode} ועל ידי # מצבים נוספים}other{ההתראות הושהו על ידי {mode} ועל ידי # מצבים נוספים}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"כן, אפשר להתחיל"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"מעקב ראש"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"יש להקיש כדי לשנות את מצב תוכנת הצלצול"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"מצב תוכנת הצלצול"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"השתקה"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ביטול ההשתקה"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"רטט"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"צריך להקיש על מקש הפעולה במקלדת"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"כל הכבוד!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"סיימת לתרגל את התנועה להצגת כל האפליקציות"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"התאורה האחורית במקלדת"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"רמה %1$d מתוך %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"שליטה במכשירים"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 1a2d0225c44f..13dd954fa891 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ウィジェットを使用してアプリを起動するには、本人確認が必要です。タブレットがロックされた状態でも他のユーザーにウィジェットが表示されますので、注意してください。一部のウィジェットについてはロック画面での使用を想定していないため、ロック画面への追加は危険な場合があります。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"OK"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ウィジェット"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"[ウィジェット] ショートカットを追加するには、設定で [ロック画面でのウィジェットの表示] が有効になっていることを確認してください。"</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"設定"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"会話"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"サイレント通知がすべて消去されます"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"サイレント モードにより通知は一時停止中です"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{通知なし}=1{{mode} により通知は一時停止中です}=2{{mode} と他 1 個のモードにより通知は一時停止中です}other{{mode} と他 # 個のモードにより通知は一時停止中です}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"今すぐ開始"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ヘッド トラッキング"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"タップすると、着信音のモードを変更できます"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"着信音のモード"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ミュート"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ミュートを解除"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"バイブレーション"</string> @@ -1426,20 +1428,17 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"キーボード ショートカット"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"キーボード ショートカットをカスタマイズする"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ショートカットを削除しますか?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"デフォルトにリセットしますか?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ショートカットを割り当てるキーを押してください"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"この操作を行うと、カスタム ショートカットが完全に削除されます。"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"この操作を行うと、すべてのカスタム ショートカットが完全に削除されます。"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"検索ショートカット"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"検索結果がありません"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"閉じるアイコン"</string> <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"アクションキーまたはメタキーのアイコン"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"プラスアイコン"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"カスタマイズ"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"リセット"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"完了"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"開くアイコン"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"または"</string> @@ -1449,8 +1448,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"キーボードの設定"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ショートカットの設定"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"削除"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"リセットする"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"キャンセル"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"キーを押してください"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"このキーの組み合わせはすでに使用されています。別のキーを試してください。"</string> @@ -1482,6 +1480,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"キーボードのアクションキーを押します"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"完了です!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"「すべてのアプリを表示する」ジェスチャーを学習しました"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"キーボード バックライト"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"レベル %1$d/%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ホーム コントロール"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index d7fe2845a520..9390bd22e1a7 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"უნდა დაადასტუროთ თქვენი ვინაობა, რათა გახსნათ აპი ვიჯეტის გამოყენებით. გაითვალისწინეთ, რომ ნებისმიერს შეუძლია მათი ნახვა, მაშინაც კი, როცა ტაბლეტი დაბლოკილია. ზოგი ვიჯეტი შეიძლება არ იყოს გათვლილი თქვენი დაბლოკილი ეკრანისთვის და მათი აქ დამატება შეიძლება სახიფათო იყოს."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"გასაგებია"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ვიჯეტები"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"„ვიჯეტების“ მალსახმობის დასამატებლად დარწმუნდით, რომ პარამეტრებში ჩართულია „დაბლოკილ ეკრანზე ვიჯეტების ჩვენება“."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"პარამეტრები"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"შეტყობინებები"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"საუბრები"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ყველა ჩუმი შეტყობინების გასუფთავება"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"შეტყობინებები დაპაუზდა „არ შემაწუხოთ“ რეჟიმის მეშვეობით"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{შეტყობინებები არ არის}=1{შეტყობინებები შეჩერებულია {mode}-ის გამო}=2{შეტყობინებები შეჩერებულია {mode}-ის და ერთი სხვა რეჟიმის გამო}other{შეტყობინებები შეჩერებულია {mode}-ის და # სხვა რეჟიმის გამო}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"დაწყება ახლავე"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ხმის მიდევნებით"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"შეეხეთ მრეკავის რეჟიმის შესაცვლელად"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"მრეკავის რეჟიმი"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"დადუმება"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"დადუმების მოხსნა"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ვიბრაცია"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"კლავიატურის მალსახმობები"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"კლავიატურის მალსახმობების მორგება"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"გსურთ მალსახმობის წაშლა?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"გსურთ ნაგულისხმევზე გადაყენება?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"მალსახმობის მინიჭებისთვის დააჭირეთ კლავიშს"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ეს თქვენს მორგებულ მალსახმობებს სამუდამოდ წაშლის."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ეს სამუდამოდ წაშლის თქვენს ყველა მორგებულ მალსახმობს."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ძიების მალსახმობები"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ძიების შედეგები არ არის"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ხატულის ჩაკეცვა"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"კლავიატურის პარამეტრები"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"მალსახმობის დაყენება"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"ამოშლა"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"დიახ, გადაყენდეს"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"გაუქმება"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"დააჭირეთ კლავიშს"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"კლავიშების კომბინაცია უკვე გამოიყენება. ცადეთ სხვა კლავიში."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"დააჭირეთ მოქმედების კლავიშს თქვენს კლავიატურაზე"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ყოჩაღ!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"თქვენ დაასრულეთ ყველა აპის ნახვის ჟესტი"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"კლავიატურის შენათება"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"დონე: %1$d %2$d-დან"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"სახლის კონტროლი"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 92269a2a2e73..672bb66dd15d 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Қолданбаны виджет көмегімен ашу үшін жеке басыңызды растауыңыз керек. Сондай-ақ басқалар оларды планшетіңіз құлыптаулы кезде де көре алатынын ескеріңіз. Кейбір виджеттер құлып экранына арналмаған болады, сондықтан оларды мұнда қосу қауіпсіз болмауы мүмкін."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Түсінікті"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виджеттер"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"Виджеттер\" таңбашасын қосу үшін параметрлерде \"Виджеттерді құлыптаулы экранда көрсету\" опциясының қосулы екенін тексеріңіз."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Параметрлер"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Хабарландырулар"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Әңгімелер"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Барлық үнсіз хабарландыруларды өшіру"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Хабарландырулар Мазаламау режимінде кідіртілді"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Хабарландырулар жоқ.}=1{Хабарландыруларды {mode} режимі кідіртті.}=2{Хабарландыруларды {mode} және тағы бір режим кідіртті.}other{Хабарландыруларды {mode} және тағы # режим кідіртті.}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Қазір бастау"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Бас қимылын қадағалау"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Қоңырау режимін өзгерту үшін түртіңіз."</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"қоңырау режимі"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дыбысын өшіру"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дыбысын қосу"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дірілдету"</string> @@ -1426,20 +1428,17 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Перне тіркесімдері"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Пернелер тіркесімін бейімдеу"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Жылдам пәрменді өшіру керек пе?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Әдепкі таңбашаларға қайтару керек пе?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Жылдам пәрменді тағайындау үшін пернені басыңыз."</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Арнаулы жылдам пәрменіңіз біржола жойылады."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Мұндайда барлық арнаулы таңбашалар біржола жойылады."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Іздеу жылдам пәрмендері"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Іздеу нәтижелері жоқ."</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жию белгішесі"</string> <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Әрекет немесе Meta пернесінің белгішесі"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Қосу белгішесі"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Бейімдеу"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Бастапқы күйге қайтару"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Дайын"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Жаю белгішесі"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"немесе"</string> @@ -1449,8 +1448,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Пернетақта параметрлері"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Жылдам пәрменді орнату"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Өшіру"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Иә, қайтару"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Бас тарту"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Пернені басыңыз"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Бұл пернелер тіркесімі қазір қолданыста. Басқа перне таңдаңыз."</string> @@ -1482,6 +1480,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Пернетақтадағы әрекет пернесін басыңыз."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Жарайсыз!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Барлық қолданбаны көру қимылын орындадыңыз."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Пернетақта жарығы"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Деңгей: %1$d/%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Үй басқару элементтері"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 13153c61ab46..96a9ed478908 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ដើម្បីបើកកម្មវិធីដោយប្រើធាតុក្រាហ្វិក អ្នកនឹងត្រូវផ្ទៀងផ្ទាត់ថាជាអ្នក។ ទន្ទឹមនឹងនេះ សូមចងចាំថា នរណាក៏អាចមើលធាតុក្រាហ្វិកបាន សូម្បីពេលថេប្លេតរបស់អ្នកជាប់សោក៏ដោយ។ ធាតុក្រាហ្វិកមួយចំនួនប្រហែលមិនត្រូវបានរចនាឡើងសម្រាប់អេក្រង់ចាក់សោរបស់អ្នកទេ និងមិនមានសុវត្ថិភាពឡើយ បើបញ្ចូលទៅទីនេះ។"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"យល់ហើយ"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ធាតុក្រាហ្វិក"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"ដើម្បីបញ្ចូលផ្លូវកាត់ \"ធាតុក្រាហ្វិក\" ត្រូវប្រាកដថា \"បង្ហាញធាតុក្រាហ្វិកនៅលើអេក្រង់ចាក់សោ\" ត្រូវបានបើកនៅក្នុងការកំណត់។"</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ការកំណត់"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"ការជូនដំណឹង"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ការសន្ទនា"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"សម្អាតការជូនដំណឹងស្ងាត់ទាំងអស់"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ការជូនដំណឹងបានផ្អាកដោយមុខងារកុំរំខាន"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{គ្មានការជូនដំណឹង}=1{ការជូនដំណឹងត្រូវបានផ្អាកដោយ {mode}}=2{ការជូនដំណឹងត្រូវបានផ្អាកដោយ {mode} និងមុខងារមួយផ្សេងទៀត}other{ការជូនដំណឹងត្រូវបានផ្អាកដោយ {mode} និងមុខងារ # ផ្សេងទៀត}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ចាប់ផ្ដើមឥឡូវ"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"រេតាមក្បាល"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ចុចដើម្បីប្ដូរមុខងាររោទ៍"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"មុខងារកម្មវិធីរោទ៍"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"បិទសំឡេង"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"បើកសំឡេង"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ញ័រ"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"ផ្លូវកាត់ក្ដារចុច"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ប្ដូរផ្លូវកាត់ក្ដារចុចតាមបំណង"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ដកផ្លូវកាត់ចេញឬ?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"កំណត់ឡើងវិញទៅលំនាំដើមឬ?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ចុចគ្រាប់ចុច ដើម្បីកំណត់ផ្លូវកាត់"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ការធ្វើបែបនេះនឹងលុបផ្លូវកាត់ផ្ទាល់ខ្លួនរបស់អ្នកជាអចិន្ត្រៃយ៍។"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"សកម្មភាពនេះនឹងលុបផ្លូវកាត់ផ្ទាល់ខ្លួនរបស់អ្នកទាំងអស់ជាអចិន្ត្រៃយ៍។"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ស្វែងរកផ្លូវកាត់"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"គ្មានលទ្ធផលស្វែងរកទេ"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"រូបតំណាង \"បង្រួម\""</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ការកំណត់ក្ដារចុច"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"កំណត់ផ្លូវកាត់"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"ដកចេញ"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"បាទ/ចាស កំណត់ឡើងវិញ"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"បោះបង់"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ចុចគ្រាប់ចុច"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"កំពុងប្រើបន្សំគ្រាប់ចុចស្រាប់ហើយ។ សាកល្បងប្រើគ្រាប់ចុចផ្សេង។"</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ចុចគ្រាប់ចុចសកម្មភាពលើក្ដារចុចរបស់អ្នក"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ធ្វើបានល្អ!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"អ្នកបានបញ្ចប់ចលនាមើលកម្មវិធីទាំងអស់ហើយ"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ពន្លឺក្រោយក្ដារចុច"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"កម្រិតទី %1$d នៃ %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ការគ្រប់គ្រងផ្ទះ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index b83e9576edca..89b8db2819c4 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ವಿಜೆಟ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಆ್ಯಪ್ ತೆರೆಯಲು, ಇದು ನೀವೇ ಎಂದು ನೀವು ದೃಢೀಕರಿಸಬೇಕಾಗುತ್ತದೆ. ಅಲ್ಲದೆ, ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಲಾಕ್ ಆಗಿದ್ದರೂ ಸಹ ಯಾರಾದರೂ ಅವುಗಳನ್ನು ವೀಕ್ಷಿಸಬಹುದು ಎಂಬುದನ್ನು ನೆನಪಿನಲ್ಲಿಡಿ. ಕೆಲವು ವಿಜೆಟ್ಗಳು ನಿಮ್ಮ ಲಾಕ್ ಸ್ಕ್ರೀನ್ಗಾಗಿ ಉದ್ದೇಶಿಸದೇ ಇರಬಹುದು ಮತ್ತು ಇಲ್ಲಿ ಸೇರಿಸುವುದು ಸುರಕ್ಷಿತವಲ್ಲದಿರಬಹುದು."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ಅರ್ಥವಾಯಿತು"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ವಿಜೆಟ್ಗಳು"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"ವಿಜೆಟ್ಗಳು\" ಶಾರ್ಟ್ಕಟ್ ಸೇರಿಸಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ \"ಲಾಕ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ವಿಜೆಟ್ಗಳನ್ನು ತೋರಿಸಿ\" ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"ಅಧಿಸೂಚನೆಗಳು"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ಸಂಭಾಷಣೆಗಳು"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ಎಲ್ಲಾ ನಿಶ್ಶಬ್ಧ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಎನ್ನುವ ಮೂಲಕ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ಯಾವುದೇ ನೋಟಿಫಿಕೇಶನ್ಗಳು ಇಲ್ಲ}=1{ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು {mode} ವಿರಾಮಗೊಳಿಸಿದೆ}=2{ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು {mode} ಹಾಗೂ ಇತರ ಒಂದು ಮೋಡ್ ವಿರಾಮಗೊಳಿಸಿವೆ}one{ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು {mode} ಹಾಗೂ ಇತರ # ಮೋಡ್ಗಳು ವಿರಾಮಗೊಳಿಸಿವೆ}other{ನೋಟಿಫಿಕೇಶನ್ಗಳನ್ನು {mode} ಹಾಗೂ ಇತರ # ಮೋಡ್ಗಳು ವಿರಾಮಗೊಳಿಸಿವೆ}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ಈಗ ಪ್ರಾರಂಭಿಸಿ"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ಹೆಡ್ ಟ್ರ್ಯಾಕಿಂಗ್"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ರಿಂಗರ್ ಮೋಡ್ ಬದಲಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ರಿಂಗರ್ ಮೋಡ್"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ಮ್ಯೂಟ್ ಮಾಡಿ"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ಅನ್ಮ್ಯೂಟ್ ಮಾಡಿ"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ವೈಬ್ರೇಟ್"</string> @@ -1426,20 +1428,17 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ತೆಗೆದುಹಾಕಬೇಕೇ?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ಡೀಫಾಲ್ಟ್ಗೆ ರೀಸೆಟ್ ಮಾಡಬೇಕೆ?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ನಿಯೋಜಿಸಲು ಕೀಯನ್ನು ಒತ್ತಿರಿ"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ಇದು ನಿಮ್ಮ ಕಸ್ಟಮ್ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ಅಳಿಸುತ್ತದೆ."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ಇದು ನಿಮ್ಮ ಎಲ್ಲಾ ಕಸ್ಟಮ್ ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ಶಾಶ್ವತವಾಗಿ ಅಳಿಸುತ್ತದೆ."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ಹುಡುಕಾಟದ ಶಾರ್ಟ್ಕಟ್ಗಳು"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ಯಾವುದೇ ಹುಡುಕಾಟ ಫಲಿತಾಂಶಗಳಿಲ್ಲ"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ಕುಗ್ಗಿಸುವ ಐಕಾನ್"</string> <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"ಆ್ಯಕ್ಷನ್ ಅಥವಾ ಮೆಟಾ ಕೀ ಐಕಾನ್"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"ಪ್ಲಸ್ ಐಕಾನ್"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"ರೀಸೆಟ್ ಮಾಡಿ"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"ಮುಗಿದಿದೆ"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"ವಿಸ್ತೃತಗೊಳಿಸುವ ಐಕಾನ್"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ಅಥವಾ"</string> @@ -1449,8 +1448,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"ಕೀಬೋರ್ಡ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ಶಾರ್ಟ್ಕಟ್ ಸೆಟ್ ಮಾಡಿ"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"ತೆಗೆದುಹಾಕಿ"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ಹೌದು, ರೀಸೆಟ್ ಮಾಡಿ"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ರದ್ದುಮಾಡಿ"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"ಕೀ ಅನ್ನು ಒತ್ತಿರಿ"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"ಕೀ ಸಂಯೋಜನೆಯು ಈಗಾಗಲೇ ಬಳಕೆಯಲ್ಲಿದೆ. ಮತ್ತೊಂದು ಕೀ ಬಳಸಿ ನೋಡಿ."</string> @@ -1482,6 +1480,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ನಲ್ಲಿ ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಒತ್ತಿ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ಭೇಷ್!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ನೀವು ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳ ಜೆಸ್ಚರ್ ವೀಕ್ಷಣೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ಕೀಬೋರ್ಡ್ ಬ್ಯಾಕ್ಲೈಟ್"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ರಲ್ಲಿ %1$d ಮಟ್ಟ"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ಮನೆ ನಿಯಂತ್ರಣಗಳು"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 00b2450881fd..276d70801cd4 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"위젯을 사용하여 앱을 열려면 본인 인증을 해야 합니다. 또한 태블릿이 잠겨 있더라도 누구나 볼 수 있다는 점을 유의해야 합니다. 일부 위젯은 잠금 화면에 적합하지 않고 여기에 추가하기에 안전하지 않을 수 있습니다."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"확인"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"위젯"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\'위젯\' 바로가기를 추가하려면 설정에서 \'잠금 화면에 위젯 표시\'가 사용 설정되어 있어야 합니다."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"설정"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"알림"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"대화"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"무음 알림 모두 삭제"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"방해 금지 모드로 알림이 일시중지됨"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{알림 없음}=1{{mode} 모드로 인해 알림이 일시중지되었습니다.}=2{{mode} 및 다른 모드로 인해 알림이 일시중지되었습니다.}other{{mode} 및 다른 모드 #개로 인해 알림이 일시중지되었습니다.}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"시작하기"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"머리 추적"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"탭하여 벨소리 장치 모드 변경"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"벨소리 장치 모드"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"음소거"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"음소거 해제"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"진동"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"단축키"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"단축키 맞춤설정"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"바로가기를 제거하시겠습니까?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"기본값으로 재설정하시겠어요?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"키를 눌러 단축키 지정"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"맞춤 단축어가 영구적으로 삭제됩니다."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"모든 맞춤 바로가기가 완전히 삭제됩니다."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"검색 바로가기"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"검색 결과 없음"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"접기 아이콘"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"키보드 설정"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"단축키 설정"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"삭제"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"재설정"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"취소"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"키를 누르세요."</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"이미 사용 중인 키 조합입니다. 다른 키를 사용해 보세요."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"키보드의 작업 키를 누르세요."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"잘하셨습니다"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"모든 앱 보기 동작을 완료했습니다."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"키보드 백라이트"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d단계 중 %1$d단계"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"홈 컨트롤"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index a857f4ecb3b4..ab20a7bd054f 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Колдонмону виджет аркылуу ачуу үчүн өзүңүздү ырасташыңыз керек. Алар кулпуланган планшетиңизде да көрүнүп турат. Кээ бир виджеттерди кулпуланган экранда колдоно албайсыз, андыктан аларды ал жерге кошпой эле койгонуңуз оң."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Түшүндүм"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виджеттер"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"Виджеттер\" ыкчам баскычын кошуу үчүн параметрлерге өтүп, \"Виджеттерди кулпуланган экранда көрсөтүү\" параметри иштетилгенин текшериңиз."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Параметрлер"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Билдирмелер"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Сүйлөшүүлөр"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бардык үнсүз билдирмелерди өчүрүү"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"Тынчымды алба\" режиминде билдирмелер тындырылды"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Билдирмелер жок}=1{{mode} режими билдирмелерди тындырды}=2{{mode} жана дагы бир режим билдирмелерди тындырды}other{{mode} жана дагы # режим билдирмелерди тындырды}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Азыр баштоо"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Баштын кыймылына көз салуу"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Коңгуроо режимин өзгөртүү үчүн басыңыз"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"коңгуроо режими"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"үнсүз"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"үнүн чыгаруу"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"дирилдөө"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Ыкчам баскычтар"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Ыкчам баскычтарды ыңгайлаштыруу"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Ыкчам баскыч өчүрүлсүнбү?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Баштапкы абалга келтиресизби?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Ыкчам баскычты дайындоо үчүн баскычты басыңыз"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Ушуну менен жеке ыкчам баскычыңыз биротоло өчүрүлөт."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Ушуну менен жеке ыкчам баскычтарыңыздын баары биротоло өчүрүлөт."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Ыкчам баскычтарды издөө"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Эч нерсе табылган жок"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Жыйыштыруу сүрөтчөсү"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Баскычтоп параметрлери"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ыкчам баскычты тууралоо"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Өчүрүү"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ооба, баштапкы абалга келтирилсин"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancel"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Баскычты басыңыз"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ачкычтардын айкалышы колдонулууда. Башка ачкычты байкап көрүңүз."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Баскычтобуңуздагы аракет баскычын басыңыз"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Эң жакшы!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Бардык колдонмолорду көрүү жаңсоосун аткардыңыз"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Баскычтоптун жарыгы"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ичинен %1$d-деңгээл"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Үйдөгү түзмөктөрдү тескөө"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 19b216d6975c..a3a25e850e52 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"ການແຈ້ງເຕືອນ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ການສົນທະນາ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ລຶບລ້າງການແຈ້ງເຕືອນແບບງຽບທັງໝົດ"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ຢຸດການແຈ້ງເຕືອນໂດຍໂໝດຫ້າມລົບກວນແລ້ວ"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ບໍ່ມີການແຈ້ງເຕືອນ}=1{{mode} ຢຸດການແຈ້ງເຕືອນໄວ້ຊົ່ວຄາວ}=2{{mode} ແລະ ອີກ 1 ໂໝດຢຸດການແຈ້ງເຕືອນໄວ້ຊົ່ວຄາວ}other{{mode} ແລະ ອີກ # ໂໝດຢຸດການແຈ້ງເຕືອນໄວ້ຊົ່ວຄາວ}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ເລີ່ມດຽວນີ້"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ການຕິດຕາມຫົວ"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ແຕະເພື່ອປ່ຽນໂໝດຣິງເກີ"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ໂໝດຣິງເກີ"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ປິດສຽງ"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ເຊົາປິດສຽງ"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ສັ່ນເຕືອນ"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ກົດປຸ່ມຄຳສັ່ງຢູ່ແປ້ນພິມຂອງທ່ານ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ດີຫຼາຍ!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ທ່ານເບິ່ງທ່າທາງຂອງແອັບທັງໝົດສຳເລັດແລ້ວ"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ໄຟປຸ່ມແປ້ນພິມ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"ລະດັບທີ %1$d ຈາກ %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ການຄວບຄຸມເຮືອນ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 6d4c775ab143..cba0db1a4e05 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Pranešimai"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Pokalbiai"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Išvalyti visus tylius pranešimus"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Pranešimai pristabdyti naudojant netrukdymo režimą"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nėra pranešimų}=1{Pranešimai pristabdyti naudojant režimą „{mode}“}=2{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar vieną režimą}one{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar # režimą}few{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar # režimus}many{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar # režimo}other{Pranešimai pristabdyti naudojant režimą „{mode}“ ir dar # režimų}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Pradėti dabar"</string> @@ -707,6 +709,7 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Galvos stebėjimas"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Palieskite, kad pakeistumėte skambučio režimą"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"skambučio režimas"</string> + <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>, palieskite, kad pakeistumėte skambučio režimą"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"nutildyti"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"įjungti garsą"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibruoti"</string> @@ -1482,6 +1485,7 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Paspauskite klaviatūros veiksmų klavišą"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Puikiai padirbėta!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Atlikote visų programų peržiūros gestą"</string> + <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Mokomoji animacija. Spustelėkite, kad pristabdytumėte ir tęstumėte atkūrimą."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatūros foninis apšvietimas"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d lygis iš %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Namų sistemos valdymas"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index d5229462285f..76980088c428 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Paziņojumi"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Sarunas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Notīrīt visus klusos paziņojumus"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Paziņojumi pārtraukti, izmantojot iestatījumu “Netraucēt”"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nav paziņojumu}=1{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” dēļ}=2{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” un vēl viena režīma dēļ}zero{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” un vēl # režīmu dēļ}one{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” un vēl # režīma dēļ}other{Paziņojumu rādīšana ir pārtraukta režīma “{mode}” un vēl # režīmu dēļ}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Sākt tūlīt"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Seko galvai"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Pieskarieties, lai mainītu zvanītāja režīmu."</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"zvanītāja režīms"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izslēgt skaņu"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ieslēgt skaņu"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrēt"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tastatūrā nospiediet darbību taustiņu."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Lieliski!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Jūs sekmīgi veicāt visu lietotņu skatīšanas žestu."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Tastatūras fona apgaismojums"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Līmenis numur %1$d, kopā ir %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Mājas kontrolierīces"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index f991c1b68aac..783e52ef01d9 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Известувања"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Избриши ги сите бесчујни известувања"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известувањата се паузирани од „Не вознемирувај“"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Нема известувања}=1{Известувањата ги паузираше {mode}}=2{Известувањата ги паузираа {mode} и уште еден режим}one{Известувањата ги паузираа {mode} и уште # режим}other{Известувањата ги паузираа {mode} и уште # режими}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Започни сега"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Следење на главата"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Допрете за да го промените режимот на ѕвончето"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"режим на ѕвонче"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"исклучен звук"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"вклучен звук"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрации"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Притиснете го копчето за дејство на тастатурата"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Браво!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Го завршивте движењето за прегледување на сите апликации"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Осветлување на тастатура"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ниво %1$d од %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Контроли за домот"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 784c896771d1..31348724b9d2 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"വിജറ്റ് ഉപയോഗിച്ച് ഒരു ആപ്പ് തുറക്കാൻ, ഇത് നിങ്ങൾ തന്നെയാണെന്ന് പരിശോധിച്ചുറപ്പിക്കേണ്ടതുണ്ട്. നിങ്ങളുടെ ടാബ്ലെറ്റ് ലോക്കായിരിക്കുമ്പോഴും എല്ലാവർക്കും അത് കാണാനാകുമെന്നതും ഓർക്കുക. ചില വിജറ്റുകൾ നിങ്ങളുടെ ലോക്ക് സ്ക്രീനിന് ഉള്ളതായിരിക്കില്ല, അവ ഇവിടെ ചേർക്കുന്നത് സുരക്ഷിതവുമായിരിക്കില്ല."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"മനസ്സിലായി"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"വിജറ്റുകൾ"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"വിജറ്റുകൾ\" കുറുക്കുവഴി ചേർക്കാൻ, ക്രമീകരണത്തിൽ \"ലോക്ക് സ്ക്രീനിൽ വിജറ്റുകൾ കാണിക്കുക\" പ്രവർത്തനക്ഷമമാക്കിയെന്ന് ഉറപ്പാക്കുക."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ക്രമീകരണം"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"അറിയിപ്പുകൾ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"സംഭാഷണങ്ങൾ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"എല്ലാ നിശബ്ദ അറിയിപ്പുകളും മായ്ക്കുക"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ശല്യപ്പെടുത്തരുത്\' വഴി അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തി"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{അറിയിപ്പുകൾ ഒന്നുമില്ല}=1{{mode}, അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തിയിരിക്കുന്നു}=2{{mode} എന്നതും മറ്റൊരു മോഡും, അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തിയിരിക്കുന്നു}other{{mode} എന്നതും മറ്റ് # മോഡുകളും, അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തിയിരിക്കുന്നു}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ഇപ്പോൾ ആരംഭിക്കുക"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ഹെഡ് ട്രാക്കിംഗ്"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"റിംഗർ മോഡ് മാറ്റാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"റിംഗർ മോഡ്"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"മ്യൂട്ട് ചെയ്യുക"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"അൺമ്യൂട്ട് ചെയ്യുക"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"വൈബ്രേറ്റ് ചെയ്യുക"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"കീബോഡ് കുറുക്കുവഴികൾ"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"കീബോർഡ് കുറുക്കുവഴികൾ ഇഷ്ടാനുസൃതമാക്കുക"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"കുറുക്കുവഴി നീക്കം ചെയ്യണോ?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ഡിഫോൾട്ടിലേക്ക് തിരികെ റീസെറ്റ് ചെയ്യണോ?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"കുറുക്കുവഴി അസൈൻ ചെയ്യാൻ കീ അമർത്തുക"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ഇത് നിങ്ങളുടെ ഇഷ്ടാനുസൃത കുറുക്കുവഴി ശാശ്വതമായി ഇല്ലാതാക്കും."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"നിങ്ങളുടെ എല്ലാ ഇഷ്ടാനുസൃത കുറുക്കുവഴികളും ശാശ്വതമായി ഇത് ഇല്ലാതാക്കും."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"തിരയൽ കുറുക്കുവഴികൾ"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"തിരയൽ ഫലങ്ങളൊന്നുമില്ല"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ചുരുക്കൽ ഐക്കൺ"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"കീബോർഡ് ക്രമീകരണം"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"കുറുക്കുവഴി സജ്ജീകരിക്കുക"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"നീക്കം ചെയ്യുക"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ഉവ്വ്, റീസെറ്റ് ചെയ്യുക"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"റദ്ദാക്കുക"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"കീ അമർത്തുക"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"കീ കോമ്പിനേഷൻ ഇതിനകം ഉപയോഗത്തിലുണ്ട്. മറ്റൊരു കീ പരീക്ഷിക്കുക."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"നിങ്ങളുടെ കീബോർഡിലെ ആക്ഷൻ കീ അമർത്തുക"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"അഭിനന്ദനങ്ങൾ!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"\'എല്ലാ ആപ്പുകളും കാണുക\' ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"കീബോഡ് ബാക്ക്ലൈറ്റ്"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-ൽ %1$d-ാമത്തെ ലെവൽ"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ഹോം കൺട്രോളുകൾ"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 6e60b718a6a1..42182bf3120e 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Мэдэгдлүүд"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Харилцан яриа"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бүх чимээгүй мэдэгдлийг арилгах"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Бүү саад бол горимын түр зогсоосон мэдэгдэл"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Мэдэгдэл байхгүй}=1{Мэдэгдлийг {mode} түр зогсоосон}=2{Мэдэгдлийг {mode} болон өөр нэг горим түр зогсоосон}other{Мэдэгдлийг {mode} болон өөр # горим түр зогсоосон}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Одоо эхлүүлэх"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Толгой хянах"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Хонхны горимыг өөрчлөхийн тулд товшино уу"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"хонхны горим"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"дууг хаах"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"дууг нээх"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"чичрэх"</string> @@ -1443,7 +1447,7 @@ <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Болсон"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Дэлгэх дүрс тэмдэг"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"эсвэл"</string> - <string name="shortcut_helper_key_combinations_and_conjunction" msgid="6138186504075880224">"нэмэх нь"</string> + <string name="shortcut_helper_key_combinations_and_conjunction" msgid="6138186504075880224">"болон"</string> <string name="shortcut_helper_key_combinations_forward_slash" msgid="1238652537199346970">"урагшаа ташуу зураас"</string> <string name="shortcut_helper_content_description_drag_handle" msgid="5092426406009848110">"Чирэх бариул"</string> <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Гарын тохиргоо"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Гар дээрх тусгай товчлуурыг дарна уу"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Сайн байна!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Та бүх аппыг харах зангааг гүйцэтгэлээ"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Гарын арын гэрэл"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d-с %1$d-р түвшин"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Гэрийн удирдлага"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index c21a666026af..b108ccc8eeee 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -113,7 +113,7 @@ <string name="screenrecord_permission_dialog_option_text_single_app" msgid="1996450687814647583">"एक अॅप रेकॉर्ड करा"</string> <string name="screenrecord_permission_dialog_option_text_entire_screen" msgid="2794896384693120020">"पूर्ण स्क्रीन रेकॉर्ड करा"</string> <string name="screenrecord_permission_dialog_option_text_entire_screen_for_display" msgid="3754611651558838691">"संपूर्ण स्क्रीन रेकॉर्ड करा: %s"</string> - <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"तुम्ही तुमची पूर्ण स्क्रीन रेकॉर्ड करता, तेव्हा तुमच्या स्क्रीनवर दाखवलेली कोणतीही गोष्टी रेकॉर्ड केली जाते. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string> + <string name="screenrecord_permission_dialog_warning_entire_screen" msgid="1321758636709366068">"तुम्ही तुमची पूर्ण स्क्रीन रेकॉर्ड करता, तेव्हा तुमच्या स्क्रीनवर दाखवलेली कोणतीही गोष्ट रेकॉर्ड केली जाते. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string> <string name="screenrecord_permission_dialog_warning_single_app" msgid="3738199712880063924">"तुम्ही अॅप रेकॉर्ड करता, तेव्हा त्या अॅपमध्ये दाखवलेली किंवा प्ले केलेली कोणतीही गोष्ट रेकॉर्ड केली जाते. त्यामुळे पासवर्ड, पेमेंट तपशील, मेसेज, फोटो आणि ऑडिओ व व्हिडिओ यांसारख्या गोष्टींबाबत सावधगिरी बाळगा."</string> <string name="screenrecord_permission_dialog_continue_entire_screen" msgid="5557974446773486600">"स्क्रीन रेकॉर्ड करा"</string> <string name="screenrecord_app_selector_title" msgid="3854492366333954736">"रेकॉर्ड करण्यासाठी अॅप निवडा"</string> @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"विजेट वापरून अॅप उघडण्यासाठी, तुम्हाला हे तुम्हीच असल्याची पडताळणी करावी लागेल. तसेच, लक्षात ठेवा, तुमचा टॅबलेट लॉक असतानादेखील कोणीही ती पाहू शकते. काही विजेट कदाचित तुमच्या लॉक स्क्रीनसाठी नाहीत आणि ती इथे जोडणे असुरक्षित असू शकते."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"समजले"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"विजेट"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"विजेट\" शॉर्टकट जोडण्यासाठी, सेटिंग्जमध्ये \"लॉक स्क्रीनवर विजेट दाखवा\" सुरू असल्याची खात्री करा."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"सेटिंग्ज"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचना"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"संभाषणे"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सर्व सायलंट सूचना साफ करा"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"व्यत्यय आणून नकाद्वारे सूचना थांबवल्या"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{कोणतेही नोटिफिकेशन नाही}=1{{mode} द्वारे नोटिफिकेशन थांबवली आहेत}=2{{mode} द्वारे आणि आणखी एका मोडद्वारे नोटिफिकेशन थांबवली आहेत}other{{mode} द्वारे आणि आणखी # मोडद्वारे नोटिफिकेशन थांबवली आहेत}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"आता सुरू करा"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"हेड ट्रॅकिंग"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"रिंगर मोड बदलण्यासाठी टॅप करा"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"रिंगर मोड"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्यूट करा"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"म्यूट काढून टाका"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"व्हायब्रेट करा"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"कीबोर्ड शॉर्टकट"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"कीबोर्ड शॉर्टकट कस्टमाइझ करा"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"शॉर्टकट काढून टाकायचा आहे का?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"डीफॉल्टवर पुन्हा रीसेट करायचे आहे का?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"शॉर्टकट असाइन करण्यासाठी की प्रेस करा"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"यामुळे तुमचा कस्टम शॉर्टकट कायमचा हटवला जाईल."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"हे तुमचे सर्व कस्टम शॉर्टकट कायमचे हटवेल."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"शोधण्यासाठी शॉर्टकट"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"कोणतेही शोध परिणाम नाहीत"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"कोलॅप्स करा आयकन"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"कीबोर्ड सेटिंग्ज"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"शॉर्टकट सेट करा"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"काढून टाका"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"होय, रीसेट करा"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"रद्द करा"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"की प्रेस करा"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"की कॉम्बिनेशन आधीपासून वापरले जात आहे. दुसरी की वापरून पहा."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"तुमच्या कीबोर्डवर अॅक्शन की प्रेस करा"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"खूप छान!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"तुम्ही ॲप्स पाहण्याचे जेश्चर पूर्ण केले आहे"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"कीबोर्ड बॅकलाइट"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d पैकी %1$d पातळी"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कंट्रोल"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 62f85a5e9fb2..6b9d6d62e80e 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widget"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Untuk menambahkan pintasan \"Widget\", pastikan \"Tunjukkan widget pada skrin kunci\" didayakan dalam tetapan."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Tetapan"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu tarik turun"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Pemberitahuan"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Perbualan"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Kosongkan semua pemberitahuan senyap"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Pemberitahuan dijeda oleh Jangan Ganggu"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Tiada pemberitahuan}=1{Pemberitahuan dijeda oleh {mode}}=2{Pemberitahuan dijeda oleh {mode} dan satu lagi mod yang lain}other{Pemberitahuan dijeda oleh {mode} dan # mod yang lain}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Mulakan sekarang"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Penjejakan Kepala"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Ketik untuk menukar mod pendering"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"mod pendering"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"redam"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"nyahredam"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"getar"</string> @@ -1426,20 +1428,17 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Pintasan papan kekunci"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sesuaikan pintasan papan kekunci"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Alih keluar pintasan?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Tetapkan kembali kepada lalai?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tekan kekunci untuk menetapkan pintasan"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Tindakan ini akan memadamkan pintasan tersuai anda secara kekal."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Tindakan ini akan memadamkan semua pintasan tersuai anda secara kekal."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pintasan carian"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Tiada hasil carian"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Kuncupkan ikon"</string> <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikon kekunci tindakan atau Meta"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikon tambah"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Sesuaikan"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Tetapkan semula"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Selesai"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Kembangkan ikon"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"atau"</string> @@ -1449,8 +1448,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Tetapan Papan Kekunci"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Tetapkan pintasan"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Alih keluar"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ya, tetapkan semula"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Batal"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tekan kekunci"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Gabungan kekunci sudah digunakan. Cuba kekunci lain."</string> @@ -1482,6 +1480,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tekan kekunci tindakan pada papan kekunci anda"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Syabas!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Anda telah melengkapkan gerak isyarat lihat semua apl"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Cahaya latar papan kekunci"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Tahap %1$d daripada %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kawalan Rumah"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 393f2f2dd46b..50f75ee552b8 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"အကြောင်းကြားချက်များ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"စကားဝိုင်းများ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"အသံတိတ် အကြောင်းကြားချက်များအားလုံးကို ရှင်းလင်းရန်"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"အကြောင်းကြားချက်များကို \'မနှောင့်ယှက်ရ\' က ခေတ္တရပ်ထားသည်"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{အကြောင်းကြားချက် မရှိပါ}=1{{mode} က ခဏရပ်ထားသော အကြောင်းကြားချက်များ}=2{{mode} နှင့် အခြားမုဒ်တစ်ခုက ခဏရပ်ထားသော အကြောင်းကြားချက်များ}other{{mode} နှင့် အခြားမုဒ် # ခုက ခဏရပ်ထားသော အကြောင်းကြားချက်များ}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ယခု စတင်ပါ"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ခေါင်းလှုပ်ရှားမှု"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ဖုန်းခေါ်သံမုဒ်သို့ ပြောင်းရန် တို့ပါ"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"အသံမြည်မုဒ်"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"အသံပိတ်ရန်"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"အသံဖွင့်ရန်"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"တုန်ခါမှု"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ကီးဘုတ်တွင် လုပ်ဆောင်ချက်ကီး နှိပ်ပါ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"အလွန်ကောင်းပါသည်။"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"အက်ပ်အားလုံးကို ကြည့်ခြင်းလက်ဟန် သင်ခန်းစာပြီးပါပြီ"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ကီးဘုတ်နောက်မီး"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"အဆင့် %2$d အနက် %1$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"အိမ်ထိန်းချုပ်မှုများ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 7454d632ee3a..f84353f0e182 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Varsler"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Fjern alle lydløse varsler"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Varsler er satt på pause av «Ikke forstyrr»"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ingen varsler}=1{Varsler er satt på pause av {mode}}=2{Varsler er satt på pause av {mode} og én modus til}other{Varsler er satt på pause av {mode} og # moduser til}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Start nå"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Hodesporing"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Trykk for å endre ringemodus"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modus for ringeprogrammet"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"kutt lyden"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på lyden"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrer"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Trykk på handlingstasten på tastaturet"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bra!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du har fullført bevegelsen for å se alle apper"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrunnslys for tastatur"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Hjemkontroller"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 9b8af93ab0d6..8fd83677334a 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचनाहरू"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"वार्तालापहरू"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सबै मौन सूचनाहरू हटाउनुहोस्"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"बाधा नपुऱ्याउनुहोस् नामक मोडमार्फत पज पारिएका सूचनाहरू"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{कुनै पनि नोटिफिकेसन छैन}=1{{mode} ले गर्दा नोटिफिकेसनहरू पज गरिएका छन्}=2{{mode} र अन्य एक मोडले गर्दा नोटिफिकेसनहरू पज गरिएका छन्}other{{mode} र अन्य # वटा मोडले गर्दा नोटिफिकेसनहरू पज गरिएका छन्}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"अहिले न"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"हेड ट्र्याकिङ"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"रिङ्गर मोड बदल्न ट्याप गर्नुहोस्"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"घण्टी बजाउने मोड"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"म्युट गर्नुहोस्"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"अनम्युट गर्नुहोस्"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"कम्पन गर्नुहोस्"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"स्याबास!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"तपाईंले जेस्चर प्रयोग गरी सबै एपहरू हेर्ने तरिका सिक्नुभएको छ"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"किबोर्ड ब्याकलाइट"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d मध्ये %1$d औँ स्तर"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"होम कन्ट्रोलहरू"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 12f415609065..d03b5fbfd190 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Als je de snelkoppeling Widgets wilt toevoegen, zorg je dat Widgets tonen op het vergrendelingsscherm aanstaat in de instellingen."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Instellingen"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Gebruiker wijzigen"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pull-downmenu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Meldingen"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekken"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle stille meldingen wissen"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Meldingen onderbroken door \'Niet storen\'"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Geen meldingen}=1{Meldingen onderbroken door {mode}}=2{Meldingen onderbroken door {mode} en 1 andere modus}other{Meldingen onderbroken door {mode} en # andere modi}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Nu starten"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Hoofdtracking"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tik om de beltoonmodus te wijzigen"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"beltoonmodus"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"geluid uit"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"geluid aanzetten"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"trillen"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Sneltoetsen"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Sneltoetsen aanpassen"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Sneltoets verwijderen?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Resetten naar standaard?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Druk op de toets om de sneltoets toe te wijzen"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Hiermee wordt je aangepaste sneltoets definitief verwijderd."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Hiermee worden al je aangepaste snelkoppelingen definitief verwijderd."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Sneltoetsen zoeken"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Geen zoekresultaten"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Icoon voor samenvouwen"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Toetsenbordinstellingen"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Sneltoets instellen"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Verwijderen"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ja, resetten"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Annuleren"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Druk op een toets"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Toetsencombinatie is al in gebruik. Probeer een andere toets."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Druk op de actietoets op het toetsenbord"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Goed gedaan!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Je weet nu hoe je het gebaar Alle apps bekijken maakt"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Achtergrondverlichting van toetsenbord"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveau %1$d van %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Bediening voor in huis"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 28d8cfc41d42..91900e7ee3df 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ସମସ୍ତ ନୀରବ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ଖାଲି କରନ୍ତୁ"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" ବିକଳ୍ପ ଦ୍ୱାରା ବିଜ୍ଞପ୍ତି ପଜ୍ ହୋଇଛି"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{କୌଣସି ବିଜ୍ଞପ୍ତି ନାହିଁ}=1{{mode} ଦ୍ୱାରା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିରତ କରାଯାଇଛି}=2{{mode} ଏବଂ ଅନ୍ୟ ଏକ ମୋଡ ଦ୍ୱାରା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିରତ କରାଯାଇଛି}other{{mode} ଏବଂ ଅନ୍ୟ # ମୋଡ ଦ୍ୱାରା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ବିରତ କରାଯାଇଛି}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ବର୍ତ୍ତମାନ ଆରମ୍ଭ କରନ୍ତୁ"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ହେଡ ଟ୍ରାକିଂ"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ରିଙ୍ଗର୍ ମୋଡ୍ ବଦଳାଇବାକୁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ରିଂଗର ମୋଡ"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ମ୍ୟୁଟ"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ଅନ୍-ମ୍ୟୁଟ୍ କରନ୍ତୁ"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ଭାଇବ୍ରେଟ୍"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ଆପଣଙ୍କର କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ବହୁତ ବଢ଼ିଆ!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ଆପଣ ସମସ୍ତ ଆପ୍ସ ଜେଶ୍ଚରକୁ ଭ୍ୟୁ କରିବା ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"କୀବୋର୍ଡ ବେକଲାଇଟ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dରୁ %1$d ନମ୍ବର ଲେଭେଲ"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ହୋମ କଣ୍ଟ୍ରୋଲ୍ସ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 9df55d6d431a..ba51bf20a0ff 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"ਸੂਚਨਾਵਾਂ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ਗੱਲਾਂਬਾਤਾਂ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ਸਾਰੀਆਂ ਸ਼ਾਂਤ ਸੂਚਨਾਵਾਂ ਕਲੀਅਰ ਕਰੋ"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਰੋਕਿਆ ਗਿਆ"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ਕੋਈ ਸੂਚਨਾ ਨਹੀਂ ਹੈ}=1{{mode} ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ}=2{{mode} ਅਤੇ ਇੱਕ ਹੋਰ ਮੋਡ ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ}other{{mode} ਅਤੇ # ਹੋਰ ਮੋਡਾਂ ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ਹੁਣੇ ਸ਼ੁਰੂ ਕਰੋ"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ਹੈੱਡ ਟਰੈਕਿੰਗ"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ਰਿੰਗਰ ਮੋਡ ਨੂੰ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ਰਿੰਗਰ ਮੋਡ"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ਮਿਊਟ ਕਰੋ"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ਅਣਮਿਊਟ ਕਰੋ"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"ਥਰਥਰਾਹਟ"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ਆਪਣੇ ਕੀ-ਬੋਰਡ \'ਤੇ ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਦਬਾਓ"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ਬਹੁਤ ਵਧੀਆ!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ਤੁਸੀਂ \'ਸਾਰੀਆਂ ਐਪਾਂ ਦੇਖੋ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ ਹੈ"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ਕੀ-ਬੋਰਡ ਬੈਕਲਾਈਟ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d ਵਿੱਚੋਂ %1$d ਪੱਧਰ"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ਹੋਮ ਕੰਟਰੋਲ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 9edb183e08d4..67856683e4a1 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widżety"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Aby dodać skrót „Widżety”, upewnij się, że opcja „Pokaż widżety na ekranie blokady” jest włączona w ustawieniach."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Ustawienia"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Powiadomienia"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Rozmowy"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Usuń wszystkie ciche powiadomienia"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Powiadomienia wstrzymane przez tryb Nie przeszkadzać"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Brak powiadomień}=1{Powiadomienia są wstrzymane przez tryb {mode}}=2{Powiadomienia są wstrzymane przez tryb {mode} i 1 inny tryb}few{Powiadomienia są wstrzymane przez tryb {mode} i # inne tryby}many{Powiadomienia są wstrzymane przez tryb {mode} i # innych trybów}other{Powiadomienia są wstrzymane przez tryb {mode} i # innego trybu}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Rozpocznij teraz"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Śledzenie głowy"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Kliknij, aby zmienić tryb dzwonka"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"tryb dzwonka"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"wycisz"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"wyłącz wyciszenie"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"włącz wibracje"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Skróty klawiszowe"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Dostosuj skróty klawiszowe"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Usunąć skrót?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Zresetować do ustawień domyślnych?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Naciśnij klawisz, aby przypisać skrót"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Spowoduje to trwałe usunięcie skrótu niestandardowego."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Spowoduje to trwałe usunięcie wszystkich skrótów niestandardowych."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Skróty do wyszukiwania"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Brak wyników wyszukiwania"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zwijania"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Ustawienia klawiatury"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Ustaw skrót"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Usuń"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Tak, zresetuj"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Anuluj"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Naciśnij klawisz"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinacja klawiszy jest już używana. Użyj innego klawisza."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Naciśnij klawisz działania na klawiaturze"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Brawo!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Znasz już gest wyświetlania wszystkich aplikacji"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podświetlenie klawiatury"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Poziom %1$d z %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Sterowanie domem"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 3871f7ab3c83..95152274b3ee 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -306,7 +306,7 @@ <string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectado"</string> <string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Compartilhamento de áudio"</string> - <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="8680997711431098238">"Compatível com compartilhamento de áudio"</string> + <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="8680997711431098238">"Aceita compartilhamento de áudio"</string> <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Salvo"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ativar"</string> @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Apagar todas as notificações silenciosas"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações pausadas pelo modo \"Não perturbe\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Sem notificações}=1{Notificações pausadas pelo modo {mode}}=2{Notificações pausadas por {mode} e mais um modo}one{Notificações pausadas por {mode} e mais # modo}many{Notificações pausadas por {mode} e mais # de modos}other{Notificações pausadas por {mode} e mais # modos}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Rastreamento de cabeça"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para mudar o modo da campainha"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modo da campainha"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string> @@ -1438,8 +1442,7 @@ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ícone da tecla de ação"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ícone de adição"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Redefinir"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Concluir"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> @@ -1482,6 +1485,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pressione a tecla de ação no teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Você concluiu o gesto para ver todos os apps"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index c0e65c74dea9..40df4c02aed9 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Widgets"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para adicionar o atalho \"Widgets\", certifique-se de que a opção \"Mostrar widgets no ecrã de bloqueio\" está ativada nas definições."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Definições"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pendente"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Limpar todas as notificações silenciosas"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações colocadas em pausa pelo modo Não incomodar."</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Sem notificações}=1{Notificações pausadas pelo modo {mode}}=2{Notificações pausadas pelo modo {mode} e mais um modo}many{Notificações pausadas pelo modo {mode} e mais # modos}other{Notificações pausadas pelo modo {mode} e mais # modos}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Começar agora"</string> @@ -707,6 +707,7 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Posição da cabeça"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para alterar o modo de campainha"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modo de som"</string> + <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>, toque para alterar o modo de som"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar som"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"reativar som"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string> @@ -1426,20 +1427,17 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Atalhos de teclado"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Personalize os atalhos de teclado"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Remover atalho?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Repor para a predefinição?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Prima a tecla para atribuir o atalho"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Esta ação elimina o atalho personalizado permanentemente."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Esta ação elimina todos os seus atalhos personalizados permanentemente."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Pesquisar atalhos"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Nenhum resultado da pesquisa"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ícone de reduzir"</string> <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ícone da tecla Meta ou de ação"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ícone de mais"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Repor"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Concluir"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone de expandir"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> @@ -1449,8 +1447,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Definições do teclado"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Configurar atalho"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Remover"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Sim, repor"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Cancelar"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Prima a tecla"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"A combinação de teclas já está a ser usada. Experimente outra tecla."</string> @@ -1482,6 +1479,7 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Prima a tecla de ação no teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Concluiu o gesto para ver todas as apps"</string> + <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Animação do tutorial, clique para pausar e retomar a reprodução."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Luz 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">"Controlos domésticos"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 3871f7ab3c83..95152274b3ee 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -306,7 +306,7 @@ <string name="turn_on_bluetooth" msgid="5681370462180289071">"Usar Bluetooth"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Conectado"</string> <string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Compartilhamento de áudio"</string> - <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="8680997711431098238">"Compatível com compartilhamento de áudio"</string> + <string name="quick_settings_bluetooth_device_audio_sharing_or_switch_active" msgid="8680997711431098238">"Aceita compartilhamento de áudio"</string> <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Salvo"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"desconectar"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"ativar"</string> @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Apagar todas as notificações silenciosas"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações pausadas pelo modo \"Não perturbe\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Sem notificações}=1{Notificações pausadas pelo modo {mode}}=2{Notificações pausadas por {mode} e mais um modo}one{Notificações pausadas por {mode} e mais # modo}many{Notificações pausadas por {mode} e mais # de modos}other{Notificações pausadas por {mode} e mais # modos}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Iniciar agora"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Rastreamento de cabeça"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Toque para mudar o modo da campainha"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modo da campainha"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"desativar o som"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ativar o som"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrar"</string> @@ -1438,8 +1442,7 @@ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ícone da tecla de ação"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ícone de adição"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Personalizar"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Redefinir"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Concluir"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ícone \"Abrir\""</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ou"</string> @@ -1482,6 +1485,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pressione a tecla de ação no teclado"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Muito bem!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Você concluiu o gesto para ver todos os apps"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <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> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 5911c405fcdd..3b5cd894d417 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificări"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversații"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Șterge toate notificările silențioase"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificări întrerupte prin „Nu deranja”"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Nicio notificare}=1{Notificările au fost întrerupte de {mode}}=2{Notificările au fost întrerupte de {mode} și de un alt mod}few{Notificările au fost întrerupte de {mode} și de alte # moduri}other{Notificările au fost întrerupte de {mode} și de alte # de moduri}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Începe acum"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Urmărirea mișcărilor capului"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Atinge pentru a schimba modul soneriei"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modul sonerie"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"dezactivează sunetul"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"activează sunetul"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibrații"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Apasă tasta de acțiuni de pe tastatură"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Felicitări!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Ai finalizat gestul pentru afișarea tuturor aplicațiilor"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Iluminarea din spate a tastaturii"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivelul %1$d din %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Comenzi pentru locuință"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 95c4ee3ffe1f..b02678738b90 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Чтобы открыть приложение, используя виджет, вам нужно будет подтвердить свою личность. Обратите внимание, что виджеты видны всем, даже если планшет заблокирован. Некоторые виджеты не предназначены для использования на заблокированном экране. Добавлять их туда может быть небезопасно."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"ОК"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виджеты"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Чтобы создать ярлык \"Виджеты\", убедитесь, что в настройках включена функция \"Показывать виджеты на заблокированном экране\"."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Настройки"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Уведомления"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговоры"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Отклонить все беззвучные уведомления"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"В режиме \"Не беспокоить\" уведомления заблокированы"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Уведомлений нет}=1{Режим \"{mode}\" приостанавливает уведомления}=2{Режим \"{mode}\" и ещё один режим приостанавливают уведомления}one{Режим \"{mode}\" и ещё # режим приостанавливают уведомления}few{Режим \"{mode}\" и ещё # режима приостанавливают уведомления}many{Режим \"{mode}\" и ещё # режимов приостанавливают уведомления}other{Режим \"{mode}\" и ещё # режима приостанавливают уведомления}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Начать"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Динамичное"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Нажмите, чтобы изменить режим звонка."</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"режим звонка"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"отключить звук"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"включить звук"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"включить вибрацию"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Быстрые клавиши"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Как настроить быстрые клавиши"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Удалить сочетание клавиш?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Сбросить настройки?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Нажмите клавишу, чтобы назначить сочетание клавиш."</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Настроенное сочетание будет безвозвратно удалено."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Все пользовательские ярлыки будут безвозвратно удалены."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Найти быстрые клавиши"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ничего не найдено"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Значок \"Свернуть\""</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Настройки клавиатуры"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Задать сочетание клавиш"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Удалить"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Сбросить"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Отмена"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Нажмите клавишу"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Это сочетание клавиш уже используется. Попробуйте другое."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Нажмите клавишу действия на клавиатуре."</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Блестяще!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Вы выполнили жест для просмотра всех приложений."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Подсветка клавиатуры"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Уровень %1$d из %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Управление домом"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 36879d6b7cb0..a496c7c69aa9 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"දැනුම් දීම්"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"සංවාද"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"සියලු නිහඬ දැනුම්දීම් හිස් කරන්න"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"බාධා නොකරන්න මගින් විරාම කරන ලද දැනුම්දීම්"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{දැනුම්දීම් නැත}=1{{mode} මගින් දැනුම්දීම් විරාම කරන ලදි}=2{{mode} සහ තව එක ප්රකාරයක් මගින් දැනුම්දීම් විරාම කරන ලදි}one{{mode} සහ තව ප්රකාර #ක් මගින් දැනුම්දීම් විරාම කරන ලදි}other{{mode} සහ තව ප්රකාර #ක් මගින් දැනුම්දීම් විරාම කරන ලදි}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"දැන් අරඹන්න"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"හිස ලුහුබැඳීම"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"නාදකය වෙනස් කිරීමට තට්ටු කරන්න"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"හඬ නඟන ආකාරය"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"නිහඬ කරන්න"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"නිශ්ශබ්දතාවය ඉවත් කරන්න"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"කම්පනය"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"ඔබේ යතුරු පුවරුවේ ක්රියාකාරී යතුර ඔබන්න"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"හොඳින් කළා!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"ඔබ සියලු යෙදුම් ඉංගිත බැලීම සම්පූර්ණ කර ඇත"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"යතුරු පුවරු පසු ආලෝකය"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dන් %1$d වැනි මට්ටම"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"නිවෙස් පාලන"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index c972c180a484..0c4880ded520 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Miniaplikácie"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Ak chcete pridať odkaz Miniaplikácie, uistite sa, že v nastaveniach je zapnutá možnosť Zobrazovať miniaplikácie na uzamknutej obrazovke."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Nastavenia"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbaľovacia ponuka"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Upozornenia"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzácie"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazať všetky tiché upozornenia"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Upozornenia sú pozastavené režimom bez vyrušení"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Žiadne upozornenia}=1{Upozornenia boli pozastavené režimom {mode}}=2{Upozornenia boli pozastavené režimom {mode} a jedným ďalším}few{Upozornenia boli pozastavené režimom {mode} a # ďalšími}many{Notifications paused by {mode} and # other modes}other{Upozornenia boli pozastavené režimom {mode} a # ďalšími}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Spustiť"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Sledovanie hlavy"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Režim zvonenia zmeníte klepnutím"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"režim zvonenia"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnite zvuk"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnite zvuk"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"zapnite vibrovanie"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Klávesové skratky"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prispôsobenie klávesových skratiek"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Chcete skratku odstrániť?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Chcete resetovať na predvolené nastavenie?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Stlačením klávesa priraďte skratku"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Týmto natrvalo odstránite vlastnú skratku."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Týmto natrvalo odstránite všetky vlastné odkazy."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Prehľadávať skratky"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Žiadne výsledky vyhľadávania"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona zbalenia"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Nastavenia klávesnice"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nastaviť skratku"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Odstrániť"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Áno, resetovať"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Zrušiť"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Stlačte kláves"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinácia klávesov sa už používa. Skúste iný kláves."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Stlačte na klávesnici akčný kláves"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Dobre!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Použili ste gesto na zobrazenie všetkých aplikácií."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Podsvietenie klávesnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. úroveň z %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Ovládanie domácnosti"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 914df7219f25..dbeed9d2a37b 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Pripomočki"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Če želite dodati bližnjico »Pripomočki«, v nastavitvah omogočite možnost »Prikaz pripomočkov na zaklenjenem zaslonu«."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Nastavitve"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"spustni meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obvestila"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Pogovori"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Brisanje vseh tihih obvestil"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Prikazovanje obvestil je začasno zaustavljeno z načinom »ne moti«"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Ni obvestil}=1{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode}}=2{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še enim drugim načinom}one{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še # drugim načinom}two{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še # drugima načinoma}few{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še # drugimi načini}other{Prikazovanje obvestil je začasno zaustavljeno z načinom {mode} in še # drugimi načini}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Začni zdaj"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Spremljanje glave"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Dotaknite se, če želite spremeniti način zvonjenja."</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"način zvonjenja"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"izklop zvoka"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"vklop zvoka"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibriranje"</string> @@ -1426,20 +1428,17 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Bližnjične tipke"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Prilagajanje bližnjičnih tipk"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Želite odstraniti bližnjico?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Želite ponastaviti na privzete bližnjice?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pritisnite tipko za dodelitev bližnjice"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"S tem boste trajno izbrisali bližnjico po meri."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"S tem boste trajno izbrisali vse bližnjice po meri."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Iskanje po bližnjicah"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Ni rezultatov iskanja"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Ikona za strnitev"</string> <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikona tipke za dejanje ali metapodatke"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Ikona znaka plus"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Prilagodi"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Ponastavi"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Končano"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikona za razširitev"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"ali"</string> @@ -1449,8 +1448,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Nastavitve tipkovnice"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Nastavite bližnjico"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Odstrani"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Da, ponastavi"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Prekliči"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pritisnite tipko"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Kombinacija tipk je že v uporabi. Poskusite z drugo tipko."</string> @@ -1482,6 +1480,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pritisnite tipko za dejanja na tipkovnici"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Odlično!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Izvedli ste potezo za ogled vseh aplikacij"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Osvetlitev tipkovnice"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Stopnja %1$d od %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrolniki za dom"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 6a597f7bd8f8..743aad0bac97 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Njoftimet"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Bisedat"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Pastro të gjitha njoftimet në heshtje"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Njoftimet janë vendosur në pauzë nga modaliteti \"Mos shqetëso\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Asnjë njoftim}=1{Njoftimet u vendosën në pauzë nga {mode}}=2{Njoftimet u vendosën në pauzë nga {mode} dhe një modalitet tjetër}other{Njoftimet u vendosën në pauzë nga {mode} dhe # modalitete të tjera}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Fillo tani"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Ndjekja e lëvizjeve të kokës"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Trokit për të ndryshuar modalitetin e ziles"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"modaliteti i ziles"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"çaktivizo audion"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"aktivizo audion"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"lësho dridhje"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Shtyp tastin e veprimit në tastierë"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Shumë mirë!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Përfundove gjestin për shikimin e të gjitha aplikacioneve"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Drita e sfondit e tastierës"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Niveli: %1$d nga %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Kontrollet e shtëpisë"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 560f4d700d22..9a15268b9a53 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"Да бисте отворили апликацију која користи виџет, треба да потврдите да сте то ви. Имајте у виду да свако може да га види, чак и када је таблет закључан. Неки виџети можда нису намењени за закључани екран и можда није безбедно да их тамо додате."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"Важи"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Виџети"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Да бисте додали пречицу Виџети, уверите се да је у подешавањима омогућено Приказуј виџете на закључаном екрану."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Подешавања"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Обавештења"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Конверзације"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Обришите сва нечујна обавештења"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Обавештења су паузирана режимом Не узнемиравај"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Нема обавештења}=1{Обавештења је паузирао {mode}}=2{Обавештења су паузирали {mode} и још један режим}one{Обавештења су паузирали {mode} и још # режим}few{Обавештења су паузирали {mode} и још # режима}other{Обавештења су паузирали {mode} и још # режима}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Започни"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Праћење главе"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Додирните да бисте променили режим звона"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"режим звона"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"искључите звук"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"укључите звук"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"вибрација"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Тастерске пречице"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Прилагодите тастерске пречице"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Желите да уклоните пречицу?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Желите да ресетујете на подразумевано?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Притисните тастер да бисте доделили пречицу"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Овим ћете трајно избрисати прилагођену пречицу."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Тиме ћете трајно избрисати све прилагођене пречице."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Претражите пречице"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Нема резултата претраге"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Икона за скупљање"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Подешавања тастатуре"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Подеси пречицу"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Уклони"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Да, ресетуј"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Откажи"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Притисните тастер"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Комбинација тастера се већ користи. Пробајте са другим тастером."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Притисните тастер радњи на тастатури"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Одлично!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Довршили сте покрет за приказивање свих апликација."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Позадинско осветљење тастатуре"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%1$d. ниво од %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Контроле за дом"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 2996033d36ad..c8fee613aa23 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Aviseringar"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konversationer"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Rensa alla ljudlösa aviseringar"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Aviseringar har pausats via Stör ej"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Inga aviseringar}=1{Aviseringar har pausats av {mode}}=2{Aviseringar har pausats av {mode} och ett annat läge}other{Aviseringar har pausats av {mode} och # andra lägen}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Starta nu"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Huvudspårning"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tryck för att ändra ringsignalens läge"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ringsignalläge"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"stänga av ljudet"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"slå på ljudet"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"vibration"</string> @@ -1438,8 +1442,7 @@ <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Ikon för åtgärdstangent"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plusikon"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Anpassa"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Återställ"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Klar"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Ikonen Utöka"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"eller"</string> @@ -1482,6 +1485,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Tryck på åtgärdstangenten på tangentbordet"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Bra gjort!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Du är klar med rörelsen för att se alla apparna."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Bakgrundsbelysning för tangentbord"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Nivå %1$d av %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Hemstyrning"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 7084bbf4d6a6..44bac9223969 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Arifa"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Mazungumzo"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Futa arifa zote zisizo na sauti"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kipengele cha Usinisumbue kimesitisha arifa"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Hakuna arifa}=1{Arifa zimesitishwa na {mode}}=2{Arifa zimesitishwa na {mode} na hali nyingine moja}other{Arifa zimesitishwa na {mode} na hali nyingine #}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Anza sasa"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Ufuatilizi wa Kichwa"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Gusa ili ubadilishe hali ya programu inayotoa milio ya simu"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"hali ya programu inayotoa milio ya simu"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"zima sauti"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"washa sauti"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tetema"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Bonyeza kitufe cha vitendo kwenye kibodi yako"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Vizuri sana!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Umekamilisha mafunzo ya mguso wa kuangalia programu zote"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Mwanga chini ya kibodi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Kiwango cha %1$d kati ya %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Dhibiti Vifaa Nyumbani"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 959e2e6d07ca..4c650958eeb1 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"அறிவிப்புகள்"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"உரையாடல்கள்"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"சைலன்ட் அறிவிப்புகள் அனைத்தையும் அழிக்கும்"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தின் மூலம் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{அறிவிப்புகள் இல்லை}=1{{mode} பயன்முறையால் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன}=2{{mode} மற்றும் வேறொரு பயன்முறையால் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன}other{{mode} மற்றும் வேறு # பயன்முறைகளால் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"இப்போது தொடங்கு"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ஹெட் டிராக்கிங்"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ரிங்கர் பயன்முறையை மாற்ற தட்டவும்"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ரிங்கர் பயன்முறை"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ஒலியடக்கும்"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ஒலி இயக்கும்"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"அதிர்வுறும்"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"உங்கள் கீபோர்டில் ஆக்ஷன் பட்டனை அழுத்தவும்"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"அருமை!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"அனைத்து ஆப்ஸையும் பார்ப்பதற்கான சைகை பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"கீபோர்டு பேக்லைட்"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"நிலை, %2$d இல் %1$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ஹோம் கன்ட்ரோல்கள்"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index a66821b05386..ebed1877810b 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"విడ్జెట్ను ఉపయోగించి యాప్ను తెరవడానికి, ఇది మీరేనని వెరిఫై చేయాల్సి ఉంటుంది. అలాగే, మీ టాబ్లెట్ లాక్ చేసి ఉన్నప్పటికీ, ఎవరైనా వాటిని చూడగలరని గుర్తుంచుకోండి. కొన్ని విడ్జెట్లు మీ లాక్ స్క్రీన్కు తగినవి కాకపోవచ్చు, వాటిని ఇక్కడ జోడించడం సురక్షితం కాకపోవచ్చు."</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"అర్థమైంది"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"విడ్జెట్లు"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"విడ్జెట్ల\" షార్ట్కట్ను జోడించడానికి, సెట్టింగ్లలో \"లాక్ స్క్రీన్లో విడ్జెట్లను చూపండి\" అనే ఆప్షన్ను ఎనేబుల్ చేసినట్లు నిర్ధారించుకోండి."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"సెట్టింగ్లు"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"నోటిఫికేషన్లు"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"సంభాషణలు"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"అన్ని నిశ్శబ్ద నోటిఫికేషన్లను క్లియర్ చేస్తుంది"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"అంతరాయం కలిగించవద్దు ద్వారా నోటిఫికేషన్లు పాజ్ చేయబడ్డాయి"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{నోటిఫికేషన్లు ఏవీ లేవు}=1{{mode} ద్వారా నోటిఫికేషన్లు పాజ్ చేయబడ్డాయి}=2{నోటిఫికేషన్లు, {mode}, మరో ఒక మోడ్ ద్వారా పాజ్ చేయబడ్డాయి}other{నోటిఫికేషన్లు, {mode}, మరో # మోడ్ల ద్వారా పాజ్ చేయబడ్డాయి}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ఇప్పుడే ప్రారంభించండి"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"హెడ్ ట్రాకింగ్"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"రింగర్ మోడ్ను మార్చడానికి ట్యాప్ చేయండి"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"రింగర్ మోడ్"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"మ్యూట్ చేయి"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"అన్మ్యూట్ చేయి"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"వైబ్రేట్"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"కీబోర్డ్ షార్ట్కట్లు"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"కీబోర్డ్ షార్ట్కట్లను అనుకూలంగా మార్చండి"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"షార్ట్కట్ను తీసివేయాలా?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"తిరిగి ఆటోమేటిక్ సెట్టింగ్కు రీసెట్ చేయాలా?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"షార్ట్కట్ను కేటాయించడానికి కీని నొక్కండి"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"ఇది మీ అనుకూల షార్ట్కట్ను శాశ్వతంగా తొలగిస్తుంది."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"ఇది మీ అనుకూల షార్ట్కట్లన్నింటిని శాశ్వతంగా తొలగిస్తుంది."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"షార్ట్కట్లను వెతకండి"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"సెర్చ్ ఫలితాలు ఏవీ లేవు"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"కుదించండి చిహ్నం"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"కీబోర్డ్ సెట్టింగ్లు"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"షార్ట్కట్ను సెట్ చేయండి"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"తీసివేయండి"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"అవును, రీసెట్ చేయాలి"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"రద్దు చేయండి"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"కీని నొక్కండి"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"కీ కాంబినేషన్ ఇప్పటికే వినియోగంలో ఉంది. వేరొక కీని ట్రై చేయండి."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"మీ కీబోర్డ్లో యాక్షన్ కీని నొక్కండి"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"చక్కగా చేశారు!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"అన్ని యాప్లను చూడడానికి ఉపయోగించే సంజ్ఞకు సంబంధించిన ట్యుటోరియల్ను మీరు పూర్తి చేశారు"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"కీబోర్డ్ బ్యాక్లైట్"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$dలో %1$dవ స్థాయి"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"హోమ్ కంట్రోల్స్"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 5ead29f4d155..fe13888c2ead 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"หากต้องการเปิดแอปโดยใช้วิดเจ็ต คุณจะต้องยืนยันตัวตนของคุณ นอกจากนี้ โปรดทราบว่าผู้อื่นจะดูวิดเจ็ตเหล่านี้ได้แม้ว่าแท็บเล็ตจะล็อกอยู่ก็ตาม วิดเจ็ตบางอย่างอาจไม่ได้มีไว้สำหรับหน้าจอล็อกของคุณ และอาจไม่ปลอดภัยที่จะเพิ่มที่นี่"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"รับทราบ"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"วิดเจ็ต"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"หากต้องการเพิ่มทางลัด \"วิดเจ็ต\" โปรดตรวจสอบว่าได้เปิดใช้ \"แสดงวิดเจ็ตในหน้าจอล็อก\" แล้วในการตั้งค่า"</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"การตั้งค่า"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"การแจ้งเตือน"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"การสนทนา"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ล้างการแจ้งเตือนแบบไม่มีเสียงทั้งหมด"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"หยุดการแจ้งเตือนชั่วคราวโดย \"ห้ามรบกวน\""</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{ไม่มีการแจ้งเตือน}=1{หยุดการแจ้งเตือนชั่วคราวโดย {mode}}=2{หยุดการแจ้งเตือนชั่วคราวโดย {mode} และโหมดอื่นอีก 1 โหมด}other{หยุดการแจ้งเตือนชั่วคราวโดย {mode} และโหมดอื่นอีก # โหมด}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"เริ่มเลย"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"การติดตามการเคลื่อนไหวของศีรษะ"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"แตะเพื่อเปลี่ยนโหมดเสียงเรียกเข้า"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"โหมดเสียงเรียกเข้า"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ปิดเสียง"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"เปิดเสียง"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"สั่น"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"แป้นพิมพ์ลัด"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"ปรับแต่งแป้นพิมพ์ลัด"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"นำแป้นพิมพ์ลัดออกใช่ไหม"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"รีเซ็ตกลับเป็นค่าเริ่มต้นไหม"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"กดแป้นเพื่อกำหนดแป้นพิมพ์ลัด"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"การดำเนินการนี้จะลบแป้นพิมพ์ลัดที่กำหนดเองอย่างถาวร"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"การดำเนินการนี้จะลบทางลัดที่กำหนดเองทั้งหมดอย่างถาวร"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"ค้นหาแป้นพิมพ์ลัด"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"ไม่พบผลการค้นหา"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"ไอคอนยุบ"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"การตั้งค่าแป้นพิมพ์"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"ตั้งค่าแป้นพิมพ์ลัด"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"นำออก"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ใช่ รีเซ็ต"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"ยกเลิก"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"กดแป้น"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"มีการใช้แป้นที่กดร่วมกันนี้แล้ว โปรดลองใช้แป้นอื่น"</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"กดปุ่มดำเนินการบนแป้นพิมพ์"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"ยอดเยี่ยม"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"คุณทำท่าทางสัมผัสเพื่อดูแอปทั้งหมดสำเร็จแล้ว"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"ไฟแบ็กไลต์ของแป้นพิมพ์"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"ระดับที่ %1$d จาก %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ระบบควบคุมอุปกรณ์สมาร์ทโฮม"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 76375a363342..9d794249b11a 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Mga Widget"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"Para idagdag ang shortcut na \"Mga Widget,\" tiyaking naka-enable ang \"Ipakita ang mga widget sa lock screen\" sa mga setting."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Mga Setting"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Mga Notification"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Mga Pag-uusap"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"I-clear ang lahat ng silent na notification"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Mga notification na na-pause ng Huwag Istorbohin"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Walang notification}=1{Na-pause ng {mode} ang mga notification}=2{Na-pause ng {mode} at isa pang mode ang mga notification}one{Na-pause ng {mode} at # pang mode ang mga notification}other{Na-pause ng {mode} at # pang mode ang mga notification}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Magsimula ngayon"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Pag-track ng Ulo"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"I-tap para baguhin ang ringer mode"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"ringer mode"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"i-mute"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"i-unmute"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"i-vibrate"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Mga keyboard shortcut"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"I-customize ang mga keyboard shortcut"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Alisin ang shortcut?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"I-reset pabalik sa default?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Pindutin ang key para magtalaga ng shortcut"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Permanente nitong ide-delete ang iyong custom na shortcut."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Permanente nitong ide-delete ang lahat ng iyong custom na shortcut."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Mga shortcut ng paghahanap"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Walang resulta ng paghahanap"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"I-collapse ang icon"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Mga Setting ng Keyboard"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Magtakda ng shortcut"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Alisin"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Oo, i-reset"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Kanselahin"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Pindutin ang key"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Ginagamit na ang kumbinasyon ng key. Sumubok ng ibang key."</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Pindutin ang action key sa iyong keyboard"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Magaling!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Nakumpleto mo ang galaw sa pag-view ng lahat ng app"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Backlight ng keyboard"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Level %1$d sa %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Mga Home Control"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index e1484e3eef4d..046d973e30ff 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirimler"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Görüşmeler"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sessiz bildirimlerin tümünü temizle"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirimler, Rahatsız Etmeyin özelliği tarafından duraklatıldı"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Bildirim yok}=1{Bildirimler {mode} tarafından duraklatıldı}=2{Bildirimler, {mode} ve bir diğer mod tarafından duraklatıldı}other{Bildirimler, {mode} ve # diğer mod tarafından duraklatıldı}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Şimdi başlat"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Baş Takibi"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Telefon zili modunu değiştirmek için dokunun"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"telefon zili modu"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"sesi kapat"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"sesi aç"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"titreşim"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klavyenizde eylem tuşuna basın"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Tebrikler!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Tüm uygulamaları görüntüleme hareketini tamamladınız"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klavye aydınlatması"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Seviye %1$d / %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Ev Kontrolleri"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index e4cc156cd454..a414824d129a 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Сповіщення"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Розмови"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Очистити всі беззвучні сповіщення"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Режим \"Не турбувати\" призупинив сповіщення"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Немає сповіщень}=1{Режим \"{mode}\" призупинив надсилання сповіщень}=2{\"{mode}\" і ще один режим призупинили надсилання сповіщень}one{\"{mode}\" і ще # режим призупинили надсилання сповіщень}few{\"{mode}\" і ще # режими призупинили надсилання сповіщень}many{\"{mode}\" і ще # режимів призупинили надсилання сповіщень}other{\"{mode}\" і ще # режиму призупинили надсилання сповіщень}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Почати зараз"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Відстеження рухів голови"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Торкніться, щоб змінити режим дзвінка"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"режим дзвінка"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"вимкнути звук"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"увімкнути звук"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"увімкнути вібросигнал"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Натисніть клавішу дії на клавіатурі"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Чудово!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Ви виконали жест для перегляду всіх додатків"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Підсвічування клавіатури"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Рівень %1$d з %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Автоматизація дому"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index def880692411..2980b2fbe0f0 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"ویجیٹ کے ذریعے ایپ کھولنے کے لیے آپ کو تصدیق کرنی ہوگی کہ یہ آپ ہی ہیں۔ نیز، ذہن میں رکھیں کہ کوئی بھی انہیں دیکھ سکتا ہے، یہاں تک کہ جب آپ کا ٹیبلیٹ مقفل ہو۔ ہو سکتا ہے کچھ ویجٹس آپ کی لاک اسکرین کے لیے نہ بنائے گئے ہوں اور یہاں شامل کرنا غیر محفوظ ہو سکتا ہے۔"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"سمجھ آ گئی"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"ویجیٹس"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"\"ویجیٹس\" شارٹ کٹ شامل کرنے کے لیے، یقینی بنائیں کہ \"مقفل اسکرین پر ویجیٹس دکھائیں\" ترتیبات میں فعال ہے۔"</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"ترتیبات"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"اطلاعات"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"گفتگوئیں"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"سبھی خاموش اطلاعات کو صاف کریں"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ڈسٹرب نہ کریں\' کے ذریعے اطلاعات کو موقوف کیا گیا"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{کوئی اطلاع نہیں ہے}=1{{mode} کی طرف سے اطلاعات کو روک دیا گیا ہے}=2{{mode} اور ایک دوسرے موڈ کے ذریعہ اطلاعات کو روک دیا گیا ہے}other{{mode} اور # دیگر طریقوں کے ذریعے اطلاعات کو روک دیا گیا ہے}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"ابھی شروع کریں"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"سر کی ٹریکنگ"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"رنگر وضع تبدیل کرنے کیلئے تھپتھپائیں"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"رنگر موڈ"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"خاموش کریں"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"غیر خاموش کریں"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"وائبریٹ"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"کی بورڈ شارٹ کٹس"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"کی بورڈ شارٹ کٹس کو حسب ضرورت بنائیں"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"شارٹ کٹ ہٹائیں؟"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"ڈیفالٹ پر واپس ری سیٹ کریں؟"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"شارٹ کٹ تفویض کرنے کے لیے کلید کو دبائیں"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"یہ آپ کا حسب ضرورت شارٹ کٹ مستقل طور پر حذف کر دے گا۔"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"یہ آپ کے تمام حسب ضرورت شارٹ کٹس کو مستقل طور پر حذف کر دے گا۔"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"تلاش کے شارٹ کٹس"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"تلاش کا کوئی نتیجہ نہیں ہے"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"آئیکن سکیڑیں"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"کی بورڈ کی ترتیبات"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"شارٹ کٹ سیٹ کریں"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"ہٹائیں"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"ہاں، ری سیٹ کریں"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"منسوخ کریں"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"کلید کو دبائیں"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"کلیدی مجموعہ پہلے سے استعمال میں ہے۔ دوسری کلید آزمائیں۔"</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"اپنے کی بورڈ پر ایکشن کلید دبائیں"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"بہت خوب!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"آپ نے سبھی ایپس دیکھیں کا اشارہ مکمل کر لیا ہے"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"کی بورڈ بیک لائٹ"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"%2$d میں سے %1$d کا لیول"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"ہوم کنٹرولز"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 9dab9e1a8d51..9057926d4cb3 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -529,10 +529,8 @@ <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> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"Vidjetlar"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"“Vidjetlar” yorligʻini qoʻshish uchun sozlamalarda “Vidjetlarni ekran qulfida chiqarish” yoqilganini tekshiring."</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"Sozlamalar"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"tortib tushiriladigan menyu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirishnomalar"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Suhbatlar"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Barcha sokin bildirishnomalarni tozalash"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bezovta qilinmasin rejimida bildirishnomalar pauza qilinadi"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Bildirishnomalar yoʻq}=1{{mode} rejimi bildirishnomalarni pauza qilgan}=2{{mode} va yana bitta boshqa rejim bildirishnomalarni pauza qilgan}other{{mode} va # ta boshqa rejim bildirishnomalarni pauza qilgan}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Boshlash"</string> @@ -707,6 +707,7 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Boshni kuzatish"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Jiringlagich rejimini oʻzgartirish uchun bosing"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"jiringlagich rejimi"</string> + <string name="volume_ringer_drawer_closed_content_description" msgid="4737792429808781745">"<xliff:g id="VOLUME_RINGER_STATUS">%1$s</xliff:g>, jiringlagich rejimini oʻzgartirish uchun bosing"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"ovozsiz qilish"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"ovozni yoqish"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"tebranish"</string> @@ -1426,20 +1427,17 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"Tezkor tugmalar"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"Tezkor tugmalarni moslash"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"Tezkor tugma olib tashlansinmi?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"Asliga qaytarilsinmi?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"Tezkor tugma sozlash uchun tugmani bosing"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"Bunda maxsus tezkor tugma butunlay oʻchirib tashlanadi."</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"Bunda barcha maxsus yorliqlaringiz butunlay oʻchirib tashlanadi."</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"Tezkor tugmalar qidiruvi"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"Hech narsa topilmadi"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"Yigʻish belgisi"</string> <string name="shortcut_helper_content_description_meta_key" msgid="3989315044342124818">"Amal bajarish uchun Meta tugmasi belgisi"</string> <string name="shortcut_helper_content_description_plus_icon" msgid="6152683734278299020">"Plus belgisi"</string> <string name="shortcut_helper_customize_button_text" msgid="3124983502748069338">"Moslash"</string> - <!-- no translation found for shortcut_helper_reset_button_text (2548243844050633472) --> - <skip /> + <string name="shortcut_helper_reset_button_text" msgid="2548243844050633472">"Tiklash"</string> <string name="shortcut_helper_done_button_text" msgid="7249905942125386191">"Tayyor"</string> <string name="shortcut_helper_content_description_expand_icon" msgid="1084435697860417390">"Yoyish belgisi"</string> <string name="shortcut_helper_key_combinations_or_separator" msgid="7082902112102125540">"yoki"</string> @@ -1449,8 +1447,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"Klaviatura sozlamalari"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"Tezkor tugma sozlash"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"Olib tashlash"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"Ha, asliga qaytarilsin"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"Bekor qilish"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"Tugmani bosing"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"Bu tugmalar birikmasi band. Boshqasini ishlating."</string> @@ -1482,6 +1479,7 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Klaviaturadagi amal tugmasini bosing"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Barakalla!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Hamma ilovalarni koʻrish ishorasini tugalladingiz"</string> + <string name="tutorial_animation_content_description" msgid="2698816574982370184">"Qoʻllanma animatsiyasi, pauza qilish va ijroni davom ettirish uchun bosing."</string> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Klaviatura orqa yoritkichi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Daraja: %1$d / %2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Uy boshqaruvi"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index c709a31b57de..6c7c5f66410f 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Thông báo"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Cuộc trò chuyện"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Xóa tất cả thông báo im lặng"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Chế độ Không làm phiền đã tạm dừng thông báo"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Không có thông báo}=1{{mode} đã tạm dừng thông báo}=2{{mode} và một chế độ khác đã tạm dừng thông báo}other{{mode} và # chế độ khác đã tạm dừng thông báo}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Bắt đầu ngay"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Theo dõi chuyển động của đầu"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Nhấn để thay đổi chế độ chuông"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"chế độ chuông"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"tắt tiếng"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"bật tiếng"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"rung"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Nhấn phím hành động trên bàn phím"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Rất tốt!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Bạn đã hoàn tất cử chỉ xem tất cả các ứng dụng"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Đèn nền bàn phím"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Độ sáng %1$d/%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Điều khiển nhà"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index a10650716c00..d37fe903da0b 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -529,10 +529,8 @@ <string name="communal_widgets_disclaimer_text" msgid="1423545475160506349">"若要使用微件打开应用,您需要验证是您本人在操作。另外请注意,任何人都可以查看此类微件,即使您的平板电脑已锁定。有些微件可能不适合显示在锁定的屏幕中,因此添加到这里可能不安全。"</string> <string name="communal_widgets_disclaimer_button" msgid="4423059765740780753">"知道了"</string> <string name="glanceable_hub_lockscreen_affordance_label" msgid="1461611028615752141">"微件"</string> - <!-- no translation found for glanceable_hub_lockscreen_affordance_disabled_text (599170482297578735) --> - <skip /> - <!-- no translation found for glanceable_hub_lockscreen_affordance_action_button_label (7636151133344609375) --> - <skip /> + <string name="glanceable_hub_lockscreen_affordance_disabled_text" msgid="599170482297578735">"如要添加“微件”快捷方式,请确保已在设置中启用“在锁屏状态下显示微件”。"</string> + <string name="glanceable_hub_lockscreen_affordance_action_button_label" msgid="7636151133344609375">"设置"</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> @@ -593,6 +591,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"对话"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有静音通知"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"勿扰模式暂停的通知"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{无通知}=1{{mode}暂停了通知}=2{{mode}和另外 1 种模式暂停了通知}other{{mode}和另外 # 种模式暂停了通知}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"立即开始"</string> @@ -707,6 +707,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"头部跟踪"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"点按即可更改振铃器模式"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"响铃模式"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"静音"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消静音"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"振动"</string> @@ -1426,12 +1428,10 @@ <string name="shortcut_helper_title" msgid="8567500639300970049">"键盘快捷键"</string> <string name="shortcut_helper_customize_mode_title" msgid="1467657117101096033">"自定义键盘快捷键"</string> <string name="shortcut_customize_mode_remove_shortcut_dialog_title" msgid="7106420484940737208">"要移除快捷键吗?"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_dialog_title (8131184731313717780) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_dialog_title" msgid="8131184731313717780">"要重置为默认快捷方式吗?"</string> <string name="shortcut_customize_mode_add_shortcut_description" msgid="6866025005347407696">"按下按键即可指定快捷键"</string> <string name="shortcut_customize_mode_remove_shortcut_description" msgid="6851287900585057128">"此操作会永久删除您的自定义快捷键。"</string> - <!-- no translation found for shortcut_customize_mode_reset_shortcut_description (2081849715634358684) --> - <skip /> + <string name="shortcut_customize_mode_reset_shortcut_description" msgid="2081849715634358684">"此操作会永久删除您的所有自定义快捷方式。"</string> <string name="shortcut_helper_search_placeholder" msgid="5488547526269871819">"搜索快捷键"</string> <string name="shortcut_helper_no_search_results" msgid="8554756497996692160">"无搜索结果"</string> <string name="shortcut_helper_content_description_collapse_icon" msgid="8028015738431664954">"收起图标"</string> @@ -1449,8 +1449,7 @@ <string name="shortcut_helper_keyboard_settings_buttons_label" msgid="6720967595915985259">"键盘设置"</string> <string name="shortcut_helper_customize_dialog_set_shortcut_button_label" msgid="4754492225010429382">"设置快捷键"</string> <string name="shortcut_helper_customize_dialog_remove_button_label" msgid="6546386970440176552">"移除"</string> - <!-- no translation found for shortcut_helper_customize_dialog_reset_button_label (7645535254306312685) --> - <skip /> + <string name="shortcut_helper_customize_dialog_reset_button_label" msgid="7645535254306312685">"是,重置"</string> <string name="shortcut_helper_customize_dialog_cancel_button_label" msgid="5595546460431741178">"取消"</string> <string name="shortcut_helper_add_shortcut_dialog_placeholder" msgid="9154297849458741995">"按下按键"</string> <string name="shortcut_customizer_key_combination_in_use_error_message" msgid="7693234470526626327">"按键组合已被使用,请尝试使用其他按键。"</string> @@ -1482,6 +1481,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按键盘上的快捷操作按键"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"非常棒!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"您已完成“查看所有应用”手势教程"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"键盘背光"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 级,共 %2$d 级"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"家居控制"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index afbd4118f6ca..9b16360bbf02 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有靜音通知"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"「請勿騷擾」模式已將通知暫停"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{沒有通知}=1{{mode}已暫停通知}=2{{mode}和另外一個模式已暫停通知}other{{mode}和另外 # 個模式已暫停通知}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"頭部追蹤"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"輕按即可變更響鈴模式"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"響鈴模式"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按下鍵盤上的快捷操作鍵"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"做得好!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"你已完成「查看所有應用程式」手勢的教學課程"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"智能家居"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 03d70e145068..49111ea40f9d 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有靜音通知"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"「零打擾」模式已將通知設為暫停"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{沒有通知}=1{「{mode}」模式已將通知設為暫停}=2{「{mode}」和另一個模式已將通知設為暫停}other{「{mode}」和另外 # 個模式已將通知設為暫停}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"立即開始"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"頭部追蹤"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"輕觸即可變更鈴聲模式"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"鈴聲模式"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"靜音"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"取消靜音"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"震動"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"按下鍵盤上的快捷操作鍵"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"非常好!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"你已完成「查看所有應用程式」手勢教學課程"</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"鍵盤背光"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"第 %1$d 級,共 %2$d 級"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"居家控制"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index b39c3e9a625b..9d4f70c40aef 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -593,6 +593,8 @@ <string name="notification_section_header_alerting" msgid="5581175033680477651">"Izaziso"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Izingxoxo"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sula zonke izaziso ezithulile"</string> + <!-- no translation found for accessibility_notification_section_header_open_settings (6235202417954844004) --> + <skip /> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Izaziso zimiswe okwesikhashana ukungaphazamisi"</string> <string name="modes_suppressing_shade_text" msgid="6037581130837903239">"{count,plural,offset:1 =0{Azikho izaziso}=1{Izaziso zimiswe okwesikhashana yi-{mode}}=2{Izaziso zimiswe okwesikhashana yi-{mode} nelinye imodi elilodwa}one{Izaziso zimiswe okwesikhashana yi-{mode} kanye namanye amamodi angu-#}other{Izaziso zimiswe okwesikhashana yi-{mode} kanye namanye amamodi angu-#}}"</string> <string name="media_projection_action_text" msgid="3634906766918186440">"Qala manje"</string> @@ -707,6 +709,8 @@ <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Ukulandelela Ikhanda"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Thepha ukuze ushintshe imodi yokukhala"</string> <string name="volume_ringer_mode" msgid="6867838048430807128">"imodi yokukhala"</string> + <!-- no translation found for volume_ringer_drawer_closed_content_description (4737792429808781745) --> + <skip /> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"thulisa"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"susa ukuthula"</string> <string name="volume_ringer_hint_vibrate" msgid="6211609047099337509">"dlidliza"</string> @@ -1482,6 +1486,8 @@ <string name="tutorial_action_key_guidance" msgid="5040613427202799294">"Cindezela inkinobho yokufinyelela kukhibhodi yakho"</string> <string name="tutorial_action_key_success_title" msgid="2371827347071979571">"Wenze kahle!"</string> <string name="tutorial_action_key_success_body" msgid="1688986269491357832">"Uqedele ukunyakazisa kokubuka onke ama-app."</string> + <!-- no translation found for tutorial_animation_content_description (2698816574982370184) --> + <skip /> <string name="keyboard_backlight_dialog_title" msgid="8273102932345564724">"Ilambu lekhibhodi"</string> <string name="keyboard_backlight_value" msgid="7336398765584393538">"Ileveli %1$d ka-%2$d"</string> <string name="home_controls_dream_label" msgid="6567105701292324257">"Izilawuli Zasekhaya"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index df7adc019a72..5894f297d2a7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1224,6 +1224,9 @@ <dimen name="min_window_blur_radius">1px</dimen> <dimen name="max_window_blur_radius">23px</dimen> + <!-- Blur radius behind Notification Shade --> + <dimen name="max_shade_window_blur_radius">60dp</dimen> + <!-- How much into a DisplayCutout's bounds we can go, on each side --> <dimen name="display_cutout_margin_consumption">0px</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 658f2c27b4cb..05c13f20f6d2 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1342,6 +1342,8 @@ <string name="glanceable_hub_lockscreen_affordance_disabled_text">To add the \"Widgets\" shortcut, make sure \"Show widgets on lock screen\" is enabled in settings.</string> <!-- Label for a button used to open Settings in order to enable showing widgets on the lock screen. [CHAR LIMIT=NONE] --> <string name="glanceable_hub_lockscreen_affordance_action_button_label">Settings</string> + <!-- Content description for a "show screensaver" button on glanceable hub. [CHAR LIMIT=NONE] --> + <string name="accessibility_glanceable_hub_to_dream_button">Show screensaver button</string> <!-- Related to user switcher --><skip/> @@ -2280,11 +2282,11 @@ <!-- User visible title for the multitasking keyboard shortcuts list. [CHAR LIMIT=70] --> <string name="keyboard_shortcut_group_system_multitasking">Multitasking</string> <!-- User visible title for the keyboard shortcut that enters split screen with current app on the right [CHAR LIMIT=70] --> - <string name="system_multitasking_rhs">Use split screen with current app on the right</string> + <string name="system_multitasking_rhs">Use split screen with app on the right</string> <!-- 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 current app on the left</string> + <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 from split screen to full screen</string> + <string name="system_multitasking_full_screen">Switch to full screen</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] --> diff --git a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt index b2d02edf3c45..a31e61f67e47 100644 --- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt @@ -107,6 +107,7 @@ constructor( activityOptions.setDisallowEnterPictureInPictureWhileLaunching(true) activityOptions.rotationAnimationHint = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS + intent.collectExtraIntentKeys() try { activityTaskManager.startActivityAsUser( null, diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index f9b30c6c2ba1..ea428698e476 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -27,6 +27,7 @@ import com.android.app.tracing.coroutines.launchTraced as launch import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey +import com.android.systemui.Flags.communalResponsiveGrid import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.communal.data.repository.CommunalMediaRepository import com.android.systemui.communal.data.repository.CommunalSmartspaceRepository @@ -535,7 +536,9 @@ constructor( // Order by creation time descending. ongoingContent.sortByDescending { it.createdTimestampMillis } // Resize the items. - ongoingContent.resizeItems() + if (!communalResponsiveGrid()) { + ongoingContent.resizeItems() + } // Return the sorted and resized items. ongoingContent diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt index da613f58dce8..c0456d5bb46e 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt @@ -110,6 +110,11 @@ sealed interface CommunalContentModel { get() = fixedHalfOrResponsiveSize() } + /** An empty spacer to reserve space in the grid. */ + data class Spacer(override val size: CommunalContentSize) : CommunalContentModel { + override val key: String = KEY.spacer() + } + /** A CTA tile in the glanceable hub view mode which can be dismissed. */ class CtaTileInViewMode : CommunalContentModel { override val key: String = KEY.CTA_TILE_IN_VIEW_MODE_KEY @@ -171,6 +176,10 @@ sealed interface CommunalContentModel { fun umo(): String { return "umo" } + + fun spacer(): String { + return "spacer_${UUID.randomUUID()}" + } } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt index a339af3694e7..5ecf2e6b2551 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt @@ -195,7 +195,7 @@ abstract class BaseCommunalViewModel( open fun onDismissCtaTile() {} /** Called as the user starts dragging a widget to reorder. */ - open fun onReorderWidgetStart(draggingItemKey: String) {} + open fun onReorderWidgetStart() {} /** Called as the user finishes dragging a widget to reorder. */ open fun onReorderWidgetEnd() {} diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt index 52bf0004cbe4..736ed5c7d336 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt @@ -164,8 +164,9 @@ constructor( ) } - override fun onReorderWidgetStart(draggingItemKey: String) { - setSelectedKey(draggingItemKey) + override fun onReorderWidgetStart() { + // Clear selection status + setSelectedKey(null) _reorderingWidgets.value = true uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START) } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt new file mode 100644 index 000000000000..7d5b196dfaa8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModel.kt @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.viewmodel + +import android.annotation.SuppressLint +import android.app.DreamManager +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.lifecycle.ExclusiveActivatable +import com.android.systemui.statusbar.policy.BatteryController +import com.android.systemui.util.kotlin.isDevicePluggedIn +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class CommunalToDreamButtonViewModel +@AssistedInject +constructor( + @Background private val backgroundContext: CoroutineContext, + batteryController: BatteryController, + private val dreamManager: DreamManager, +) : ExclusiveActivatable() { + + private val _requests = Channel<Unit>(Channel.BUFFERED) + + /** Whether we should show a button on hub to switch to dream. */ + @SuppressLint("MissingPermission") + val shouldShowDreamButtonOnHub = + batteryController + .isDevicePluggedIn() + .distinctUntilChanged() + .map { isPluggedIn -> isPluggedIn && dreamManager.canStartDreaming(true) } + .flowOn(backgroundContext) + + /** Handle a tap on the "show dream" button. */ + fun onShowDreamButtonTap() { + _requests.trySend(Unit) + } + + @SuppressLint("MissingPermission") + override suspend fun onActivated(): Nothing = coroutineScope { + launch { + _requests.receiveAsFlow().collectLatest { + withContext(backgroundContext) { dreamManager.startDream() } + } + } + + awaitCancellation() + } + + @AssistedFactory + interface Factory { + fun create(): CommunalToDreamButtonViewModel + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/util/ResizeUtils.kt b/packages/SystemUI/src/com/android/systemui/communal/util/ResizeUtils.kt new file mode 100644 index 000000000000..36cc1c051336 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/util/ResizeUtils.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS 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.communal.util + +import com.android.systemui.communal.domain.model.CommunalContentModel +import com.android.systemui.communal.shared.model.CommunalContentSize + +object ResizeUtils { + /** + * Resizes ongoing items such that we don't mix regular content with ongoing content. + * + * NOTE: This is *NOT* a pure function, as it modifies items in the input list. + * + * Assumptions: + * 1. Ongoing content is always at the start of the list. + * 2. The maximum size of ongoing content is 2 rows. + */ + fun resizeOngoingItems( + list: List<CommunalContentModel>, + numRows: Int, + ): List<CommunalContentModel> { + val finalizedList = mutableListOf<CommunalContentModel>() + val numOngoing = list.count { it is CommunalContentModel.Ongoing } + // Calculate the number of extra rows we have if each ongoing item were to take up a single + // row. This is the number of rows we have to distribute across items. + var extraRows = + if (numOngoing % numRows == 0) { + 0 + } else { + numRows - (numOngoing % numRows) + } + var remainingRows = numRows + + for (item in list) { + if (item is CommunalContentModel.Ongoing) { + if (remainingRows == 0) { + // Start a new column. + remainingRows = numRows + } + val newSize = if (extraRows > 0 && remainingRows > 1) 2 else 1 + item.size = CommunalContentSize.Responsive(newSize) + finalizedList.add(item) + extraRows -= (newSize - 1) + remainingRows -= newSize + } else { + if (numOngoing > 0 && remainingRows > 0) { + finalizedList.add( + CommunalContentModel.Spacer(CommunalContentSize.Responsive(remainingRows)) + ) + } + remainingRows = -1 + finalizedList.add(item) + } + } + return finalizedList + } +} diff --git a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt index 7242770e72e5..e2646353bc19 100644 --- a/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractor.kt @@ -21,6 +21,9 @@ import com.android.systemui.CoreStartable import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.contextualeducation.GestureType import com.android.systemui.contextualeducation.GestureType.ALL_APPS +import com.android.systemui.contextualeducation.GestureType.BACK +import com.android.systemui.contextualeducation.GestureType.HOME +import com.android.systemui.contextualeducation.GestureType.OVERVIEW import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.education.ContextualEducationMetricsLogger @@ -37,6 +40,7 @@ import com.android.systemui.recents.OverviewProxyService import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import java.time.Clock +import java.time.Instant import javax.inject.Inject import kotlin.time.Duration import kotlin.time.Duration.Companion.days @@ -48,6 +52,7 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.merge @@ -71,6 +76,8 @@ constructor( const val TAG = "KeyboardTouchpadEduInteractor" const val MAX_SIGNAL_COUNT: Int = 2 const val MAX_EDUCATION_SHOW_COUNT: Int = 2 + const val MAX_TOAST_PER_USAGE_SESSION: Int = 2 + val usageSessionDuration = getDurationForConfig("persist.contextual_edu.usage_session_sec", 3.days) val minIntervalBetweenEdu = @@ -110,6 +117,16 @@ constructor( awaitClose { overviewProxyService.removeCallback(listener) } } + private val gestureModelMap: Flow<Map<GestureType, GestureEduModel>> = + combine( + contextualEducationInteractor.backGestureModelFlow, + contextualEducationInteractor.homeGestureModelFlow, + contextualEducationInteractor.overviewGestureModelFlow, + contextualEducationInteractor.allAppsGestureModelFlow, + ) { back, home, overview, allApps -> + mapOf(BACK to back, HOME to home, OVERVIEW to overview, ALL_APPS to allApps) + } + @OptIn(ExperimentalCoroutinesApi::class) override fun start() { backgroundScope.launch { @@ -211,7 +228,11 @@ constructor( private suspend fun incrementSignalCount(gestureType: GestureType) { val targetDevice = getTargetDevice(gestureType) - if (isTargetDeviceConnected(targetDevice) && hasInitialDelayElapsed(targetDevice)) { + if ( + isTargetDeviceConnected(targetDevice) && + hasInitialDelayElapsed(targetDevice) && + isMinIntervalForToastEduElapsed(gestureType) + ) { contextualEducationInteractor.incrementSignalCount(gestureType) } } @@ -223,6 +244,28 @@ constructor( } } + private suspend fun isMinIntervalForToastEduElapsed(gestureType: GestureType): Boolean { + val gestureModelMap = gestureModelMap.first() + // Only perform checking if the next edu is toast (i.e. no education is shown yet) + if (gestureModelMap[gestureType]?.educationShownCount != 0) { + return true + } + + val wasLastEduToast = { gesture: GestureEduModel -> gesture.educationShownCount == 1 } + val toastEduTimesInCurrentSession: List<Instant> = + gestureModelMap.values + .filter { wasLastEduToast(it) } + .mapNotNull { it.lastEducationTime } + .filter { it >= clock.instant().minusSeconds(usageSessionDuration.inWholeSeconds) } + + return if (toastEduTimesInCurrentSession.size >= MAX_TOAST_PER_USAGE_SESSION) { + val lastToastTime: Instant? = toastEduTimesInCurrentSession.maxOrNull() + clock.instant().isAfter(lastToastTime?.plusSeconds(usageSessionDuration.inWholeSeconds)) + } else { + true + } + } + /** * Keyboard shortcut education would be provided for All Apps. Touchpad gesture education would * be provided for the rest of the gesture types (i.e. Home, Overview, Back). This method maps diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt index eab752877520..85725d24758d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt @@ -368,8 +368,8 @@ constructor( SceneContainerFlag.isEnabled, ) ) - val startPadding: Int = smartspaceViewModel.getSmartspaceStartPadding(previewContext) - val endPadding: Int = smartspaceViewModel.getSmartspaceEndPadding(previewContext) + val startPadding: Int = smartspaceViewModel.getDateWeatherStartPadding(previewContext) + val endPadding: Int = smartspaceViewModel.getDateWeatherEndPadding(previewContext) smartSpaceView?.let { it.setPaddingRelative(startPadding, topPadding, endPadding, 0) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt index d54d411b7de6..73e14b1524f3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt @@ -33,8 +33,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.binder.KeyguardSmartspaceViewBinder import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel -import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.res.R as R +import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shared.R as sharedR import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController import dagger.Lazy @@ -113,8 +113,9 @@ constructor( override fun applyConstraints(constraintSet: ConstraintSet) { if (!MigrateClocksToBlueprint.isEnabled) return if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return - val horizontalPaddingStart = KeyguardSmartspaceViewModel.getSmartspaceStartMargin(context) - val horizontalPaddingEnd = KeyguardSmartspaceViewModel.getSmartspaceEndMargin(context) + val dateWeatherPaddingStart = KeyguardSmartspaceViewModel.getDateWeatherStartMargin(context) + val smartspaceHorizontalPadding = + KeyguardSmartspaceViewModel.getSmartspaceHorizontalMargin(context) constraintSet.apply { // migrate addDateWeatherView, addWeatherView from KeyguardClockSwitchController constrainHeight(sharedR.id.date_smartspace_view, ConstraintSet.WRAP_CONTENT) @@ -124,7 +125,7 @@ constructor( ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, - horizontalPaddingStart, + dateWeatherPaddingStart, ) // migrate addSmartspaceView from KeyguardClockSwitchController @@ -135,7 +136,7 @@ constructor( ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, - horizontalPaddingStart, + smartspaceHorizontalPadding, ) connect( sharedR.id.bc_smartspace_view, @@ -143,7 +144,7 @@ constructor( if (keyguardSmartspaceViewModel.isShadeLayoutWide.value) R.id.split_shade_guideline else ConstraintSet.PARENT_ID, ConstraintSet.END, - horizontalPaddingEnd, + smartspaceHorizontalPadding, ) if (keyguardClockViewModel.hasCustomWeatherDataDisplay.value) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt index 0280d17f4ae2..15b696e71164 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewSmartspaceViewModel.kt @@ -62,12 +62,12 @@ constructor( overrideClockSize.value = clockSize } - fun getSmartspaceStartPadding(context: Context): Int { - return KeyguardSmartspaceViewModel.getSmartspaceStartMargin(context) + fun getDateWeatherStartPadding(context: Context): Int { + return KeyguardSmartspaceViewModel.getDateWeatherStartMargin(context) } - fun getSmartspaceEndPadding(context: Context): Int { - return KeyguardSmartspaceViewModel.getSmartspaceEndMargin(context) + fun getDateWeatherEndPadding(context: Context): Int { + return KeyguardSmartspaceViewModel.getDateWeatherEndMargin(context) } /* diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt index 3266dc45427a..5ee80a7b7442 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt @@ -94,14 +94,19 @@ constructor( val isShadeLayoutWide: StateFlow<Boolean> = shadeInteractor.isShadeLayoutWide companion object { - fun getSmartspaceStartMargin(context: Context): Int { + fun getDateWeatherStartMargin(context: Context): Int { return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start) + context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal) } - fun getSmartspaceEndMargin(context: Context): Int { + fun getDateWeatherEndMargin(context: Context): Int { return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end) + context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal) } + + fun getSmartspaceHorizontalMargin(context: Context): Int { + return context.resources.getDimensionPixelSize(R.dimen.smartspace_padding_horizontal) + + context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS b/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS index 95b8fa74feeb..4976d94d9057 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS @@ -1,3 +1,3 @@ # Bug component: 1280508 -# Files in this directory should still be reviewed by a member of SystemUI team +asapperstein@google.com diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java index 2fda2013d6f5..d33ad8f80021 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java @@ -122,21 +122,20 @@ public class MediaProjectionPermissionActivity extends Activity { final Intent launchingIntent = getIntent(); mReviewGrantedConsentRequired = launchingIntent.getBooleanExtra( EXTRA_USER_REVIEW_GRANTED_CONSENT, false); - if (com.android.systemui.Flags.mediaProjectionRequestAttributionFix()) { - mPackageName = getLaunchedFromPackage(); - } else { - mPackageName = getCallingPackage(); - } - // This activity is launched directly by an app, or system server. System server provides - // the package name through the intent if so. - if (mPackageName == null || ( - com.android.systemui.Flags.mediaProjectionRequestAttributionFix() - && getCallingPackage() == null)) { + // The original requester of this activity start + mPackageName = getLaunchedFromPackage(); + + // This activity is launched directly by using startActivity(), + // thus getCallingPackage() will be null. + if (getCallingPackage() == null) { + // System server provides the package name through the intent if so and is able to get + // the result back. Other applications can't. if (launchingIntent.hasExtra(EXTRA_PACKAGE_REUSING_GRANTED_CONSENT)) { mPackageName = launchingIntent.getStringExtra( EXTRA_PACKAGE_REUSING_GRANTED_CONSENT); } else { + // The activity was not launched for result, we abort here finishAsCancelled(); return; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java index 94b8a3ac5a3c..1205c87b2d95 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java @@ -16,55 +16,10 @@ package com.android.systemui.qs.dagger; -import com.android.systemui.media.dagger.MediaModule; -import com.android.systemui.qs.ReduceBrightColorsController; -import com.android.systemui.qs.ReduceBrightColorsControllerImpl; -import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeModule; -import com.android.systemui.qs.external.QSExternalModule; -import com.android.systemui.qs.panels.dagger.PanelsModule; -import com.android.systemui.qs.pipeline.dagger.QSPipelineModule; -import com.android.systemui.qs.tileimpl.QSTileImpl; -import com.android.systemui.qs.tiles.di.QSTilesModule; -import com.android.systemui.qs.ui.adapter.QSSceneAdapter; -import com.android.systemui.qs.ui.adapter.QSSceneAdapterImpl; - -import java.util.Map; - -import dagger.Binds; import dagger.Module; -import dagger.multibindings.Multibinds; /** - * Module for QS dependencies + * Module for QS dependencies for AOSP inclusion */ -@Module(subcomponents = {QSFragmentComponent.class, QSSceneComponent.class}, - includes = { - MediaModule.class, - PanelsModule.class, - QSFragmentComposeModule.class, - QSExternalModule.class, - QSFlagsModule.class, - QSHostModule.class, - QSPipelineModule.class, - QSTilesModule.class, - } -) -public interface QSModule { - - /** - * A map of internal QS tiles. Ensures that this can be injected even if - * it is empty - */ - @Multibinds - Map<String, QSTileImpl<?>> tileMap(); - - @Binds - QSSceneAdapter bindsQsSceneInteractor(QSSceneAdapterImpl impl); - - /** - * Dims the screen - */ - @Binds - ReduceBrightColorsController bindReduceBrightColorsController( - ReduceBrightColorsControllerImpl impl); -} +@Module(includes = { QSModuleBase.class}) +public interface QSModule { } diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModuleBase.kt b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModuleBase.kt new file mode 100644 index 000000000000..3fd87689b169 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModuleBase.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.qs.dagger + +import com.android.systemui.media.dagger.MediaModule +import com.android.systemui.qs.ReduceBrightColorsController +import com.android.systemui.qs.ReduceBrightColorsControllerImpl +import com.android.systemui.qs.composefragment.dagger.QSFragmentComposeModule +import com.android.systemui.qs.external.QSExternalModule +import com.android.systemui.qs.panels.dagger.PanelsModule +import com.android.systemui.qs.pipeline.dagger.QSPipelineModule +import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tiles.di.QSTilesModule +import com.android.systemui.qs.ui.adapter.QSSceneAdapter +import com.android.systemui.qs.ui.adapter.QSSceneAdapterImpl +import dagger.Binds +import dagger.Module +import dagger.multibindings.Multibinds + +/** + * QS Module for shared dependencies between AOSP and variants. Include this module in more + * specialized modules (like [QSModule]) and do not include this module directly in SystemUI modules + */ +@Module( + subcomponents = [QSFragmentComponent::class, QSSceneComponent::class], + includes = + [ + MediaModule::class, + PanelsModule::class, + QSFragmentComposeModule::class, + QSExternalModule::class, + QSFlagsModule::class, + QSHostModule::class, + QSPipelineModule::class, + QSTilesModule::class, + ], +) +interface QSModuleBase { + + /** A map of internal QS tiles. Ensures that this can be injected even if it is empty */ + @Multibinds fun tileMap(): Map<String?, QSTileImpl<*>?>? + + @Binds fun bindsQsSceneAdapter(impl: QSSceneAdapterImpl?): QSSceneAdapter? + + /** Dims the screen */ + @Binds + fun bindReduceBrightColorsController( + impl: ReduceBrightColorsControllerImpl? + ): ReduceBrightColorsController? +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt index ead38f3f9b52..ef45ae76c20c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt @@ -209,7 +209,7 @@ constructor( // TODO(b/250618218): Remove this method once we know the root cause of b/250618218. fun logTileBackgroundColorUpdateIfInternetTile( - tileSpec: String, + tileSpec: String?, state: Int, disabledByPolicy: Boolean, color: Int, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt index 17b78ebf106c..e8c4274474e0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/interactor/QSTileUserActionInteractor.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles.base.interactor import android.annotation.WorkerThread +import com.android.systemui.plugins.qs.TileDetailsViewModel interface QSTileUserActionInteractor<DATA_TYPE> { /** @@ -27,4 +28,17 @@ interface QSTileUserActionInteractor<DATA_TYPE> { * It's safe to run long running computations inside this function. */ @WorkerThread suspend fun handleInput(input: QSTileInput<DATA_TYPE>) + + /** + * Provides the [TileDetailsViewModel] for constructing the corresponding details view. + * + * This property is defined here to reuse the business logic. For example, reusing the user + * long-click as the go-to-settings callback in the details view. + * Subclasses can override this property to provide a specific [TileDetailsViewModel] + * implementation. + * + * @return The [TileDetailsViewModel] instance, or null if not implemented. + */ + val detailsViewModel: TileDetailsViewModel? + get() = null } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt index aeb6cef162b5..224fa104168d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt @@ -20,6 +20,7 @@ import android.os.UserHandle import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.Dumpable import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger import com.android.systemui.qs.tiles.base.interactor.DisabledByPolicyInteractor @@ -115,6 +116,9 @@ class QSTileViewModelImpl<DATA_TYPE>( .flowOn(backgroundDispatcher) .stateIn(tileScope, SharingStarted.WhileSubscribed(), true) + override val detailsViewModel: TileDetailsViewModel? + get() = userActionInteractor().detailsViewModel + override fun forceUpdate() { tileScope.launch(context = backgroundDispatcher) { forceUpdates.emit(Unit) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index bed802163b1a..dbe1ae90b3f6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -195,8 +195,11 @@ public class InternetDialogController implements AccessPointController.AccessPoi private boolean mHasWifiEntries; private WifiStateWorker mWifiStateWorker; private boolean mHasActiveSubIdOnDds; + private boolean mIsMobileDataEnabled = false; @VisibleForTesting + Map<Integer, ServiceState> mSubIdServiceState = new HashMap<>(); + @VisibleForTesting static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f; @VisibleForTesting static final float TOAST_PARAMS_VERTICAL_WEIGHT = 1.0f; @@ -453,7 +456,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE); } - if (mCanConfigWifi && !isMobileDataEnabled()) { + if (mCanConfigWifi && !mIsMobileDataEnabled) { if (DEBUG) { Log.d(TAG, "Mobile data off"); } @@ -551,7 +554,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi numLevels += 1; } return getSignalStrengthIcon(subId, mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, - !isMobileDataEnabled()); + !mIsMobileDataEnabled); } Drawable getSignalStrengthIcon(int subId, Context context, int level, int numLevels, @@ -681,6 +684,12 @@ public class InternetDialogController implements AccessPointController.AccessPoi // sets the non-DDS to be not found to hide its visual return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } + int activeDataSubId = SubscriptionManager.getActiveDataSubscriptionId(); + if (activeDataSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID + || mDefaultDataSubId == activeDataSubId) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo( SubscriptionManager.getActiveDataSubscriptionId()); if (subInfo != null && subInfo.getSubscriptionId() != mDefaultDataSubId @@ -740,7 +749,6 @@ public class InternetDialogController implements AccessPointController.AccessPoi if (!isMobileDataEnabled()) { return context.getString(R.string.mobile_data_off_summary); } - String summary = networkTypeDescription; boolean isForDds = subId == mDefaultDataSubId; int activeSubId = getActiveAutoSwitchNonDdsSubId(); @@ -753,8 +761,8 @@ public class InternetDialogController implements AccessPointController.AccessPoi context.getString( isForDds // if nonDds is active, explains Dds status as poor connection ? (isOnNonDds ? R.string.mobile_data_poor_connection - : R.string.mobile_data_connection_active) - : R.string.mobile_data_temp_connection_active), + : R.string.mobile_data_connection_active) + : R.string.mobile_data_temp_connection_active), networkTypeDescription); } else if (!isDataStateInService(subId)) { summary = context.getString(R.string.mobile_data_no_connection); @@ -963,10 +971,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi * Return {@code true} if mobile data is enabled */ boolean isMobileDataEnabled() { - if (mTelephonyManager == null || !mTelephonyManager.isDataEnabled()) { - return false; - } - return true; + return mIsMobileDataEnabled; } /** @@ -1019,8 +1024,8 @@ public class InternetDialogController implements AccessPointController.AccessPoi } boolean isDataStateInService(int subId) { - TelephonyManager tm = mSubIdTelephonyManagerMap.getOrDefault(subId, mTelephonyManager); - final ServiceState serviceState = tm.getServiceState(); + final ServiceState serviceState = mSubIdServiceState.getOrDefault(subId, + new ServiceState()); NetworkRegistrationInfo regInfo = (serviceState == null) ? null : serviceState.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, @@ -1036,8 +1041,8 @@ public class InternetDialogController implements AccessPointController.AccessPoi return false; } - TelephonyManager tm = mSubIdTelephonyManagerMap.getOrDefault(subId, mTelephonyManager); - final ServiceState serviceState = tm.getServiceState(); + final ServiceState serviceState = mSubIdServiceState.getOrDefault(subId, + new ServiceState()); return serviceState != null && serviceState.getState() == serviceState.STATE_IN_SERVICE; } @@ -1056,6 +1061,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi final Network activeNetwork = mConnectivityManager.getActiveNetwork(); if (activeNetwork == null) { + Log.d(TAG, "getActiveNetwork is null."); return false; } final NetworkCapabilities networkCapabilities = @@ -1183,14 +1189,16 @@ public class InternetDialogController implements AccessPointController.AccessPoi } private class InternetTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.DataEnabledListener, TelephonyCallback.DataConnectionStateListener, TelephonyCallback.DisplayInfoListener, TelephonyCallback.ServiceStateListener, TelephonyCallback.SignalStrengthsListener, TelephonyCallback.UserMobileDataStateListener, - TelephonyCallback.CarrierNetworkListener{ + TelephonyCallback.CarrierNetworkListener { private final int mSubId; + private InternetTelephonyCallback(int subId) { mSubId = subId; } @@ -1200,6 +1208,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi if (mCallback != null) { mCallback.onServiceStateChanged(serviceState); } + mSubIdServiceState.put(mSubId, serviceState); } @Override @@ -1238,6 +1247,13 @@ public class InternetDialogController implements AccessPointController.AccessPoi mCallback.onCarrierNetworkChange(active); } } + + @Override + public void onDataEnabledChanged(boolean b, int i) { + if (mSubId == mDefaultDataSubId) { + mIsMobileDataEnabled = b; + } + } } private class InternetOnSubscriptionChangedListener diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java index 0ab533bb9838..378d553065e0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java @@ -416,9 +416,10 @@ public class InternetDialogDelegate implements internetContent.mHasEthernet = mInternetDialogController.hasEthernet(); internetContent.mIsWifiEnabled = mInternetDialogController.isWifiEnabled(); internetContent.mHasActiveSubIdOnDds = mInternetDialogController.hasActiveSubIdOnDds(); - internetContent.mIsMobileDataEnabled = mInternetDialogController.isMobileDataEnabled(); internetContent.mIsDeviceLocked = mInternetDialogController.isDeviceLocked(); internetContent.mIsWifiScanEnabled = mInternetDialogController.isWifiScanEnabled(); + internetContent.mActiveAutoSwitchNonDdsSubId = + mInternetDialogController.getActiveAutoSwitchNonDdsSubId(); return internetContent; } @@ -433,7 +434,11 @@ public class InternetDialogDelegate implements private void setOnClickListener(SystemUIDialog dialog) { mMobileNetworkLayout.setOnClickListener(v -> { - int autoSwitchNonDdsSubId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId(); + int autoSwitchNonDdsSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + if (mDataInternetContent.getValue() != null) { + autoSwitchNonDdsSubId = + mDataInternetContent.getValue().mActiveAutoSwitchNonDdsSubId; + } if (autoSwitchNonDdsSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { showTurnOffAutoDataSwitchDialog(dialog, autoSwitchNonDdsSubId); } @@ -524,7 +529,7 @@ public class InternetDialogDelegate implements } } else { mMobileNetworkLayout.setVisibility(View.VISIBLE); - mMobileDataToggle.setChecked(internetContent.mIsMobileDataEnabled); + mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled()); mMobileTitleText.setText(getMobileNetworkTitle(mDefaultDataSubId)); String summary = getMobileNetworkSummary(mDefaultDataSubId); if (!TextUtils.isEmpty(summary)) { @@ -549,9 +554,9 @@ public class InternetDialogDelegate implements ? R.color.connected_network_primary_color : R.color.disconnected_network_primary_color; mMobileToggleDivider.setBackgroundColor(dialog.getContext().getColor(primaryColor)); - // Display the info for the non-DDS if it's actively being used - int autoSwitchNonDdsSubId = mInternetDialogController.getActiveAutoSwitchNonDdsSubId(); + int autoSwitchNonDdsSubId = internetContent.mActiveAutoSwitchNonDdsSubId; + int nonDdsVisibility = autoSwitchNonDdsSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID ? View.VISIBLE : View.GONE; @@ -983,8 +988,8 @@ public class InternetDialogDelegate implements boolean mIsCarrierNetworkActive = false; boolean mIsWifiEnabled = false; boolean mHasActiveSubIdOnDds = false; - boolean mIsMobileDataEnabled = false; boolean mIsDeviceLocked = false; boolean mIsWifiScanEnabled = false; + int mActiveAutoSwitchNonDdsSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt index a963b2875154..c4f9515b819f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/internet/domain/interactor/InternetTileUserActionInteractor.kt @@ -18,10 +18,13 @@ package com.android.systemui.qs.tiles.impl.internet.domain.interactor import android.content.Intent import android.provider.Settings +import com.android.systemui.animation.Expandable import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor +import com.android.systemui.qs.tiles.dialog.InternetDetailsViewModel import com.android.systemui.qs.tiles.dialog.InternetDialogManager import com.android.systemui.qs.tiles.dialog.WifiStateWorker import com.android.systemui.qs.tiles.impl.internet.domain.model.InternetTileModel @@ -61,11 +64,18 @@ constructor( wifiStateWorker.isWifiEnabled = !wifiStateWorker.isWifiEnabled } is QSTileUserAction.LongClick -> { - qsTileIntentUserActionHandler.handle( - action.expandable, - Intent(Settings.ACTION_WIFI_SETTINGS) - ) + handleLongClick(action.expandable) } } } + + override val detailsViewModel: TileDetailsViewModel = + InternetDetailsViewModel { handleLongClick(null) } + + private fun handleLongClick(expandable:Expandable?){ + qsTileIntentUserActionHandler.handle( + expandable, + Intent(Settings.ACTION_WIFI_SETTINGS) + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt index b1b0001b6361..e8b9926e5cea 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles.viewmodel import android.os.UserHandle +import com.android.systemui.plugins.qs.TileDetailsViewModel import kotlinx.coroutines.flow.StateFlow /** @@ -37,6 +38,10 @@ interface QSTileViewModel { /** Specifies whether this device currently supports this tile. */ val isAvailable: StateFlow<Boolean> + /** Specifies the [TileDetailsViewModel] for constructing the corresponding details view. */ + val detailsViewModel: TileDetailsViewModel? + get() = null + /** * Notifies about the user change. Implementations should avoid using 3rd party userId sources * and use this value instead. This is to maintain consistent and concurrency-free behaviour diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt index 9d902d39efff..632eeefcb462 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt @@ -27,6 +27,7 @@ import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.UiBackground import com.android.systemui.plugins.qs.QSTile +import com.android.systemui.plugins.qs.TileDetailsViewModel import com.android.systemui.qs.QSHost import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIconWithRes @@ -154,6 +155,10 @@ constructor( qsTileViewModel.onUserChanged(UserHandle.of(currentUser)) } + override fun getDetailsViewModel(): TileDetailsViewModel? { + return qsTileViewModel.detailsViewModel + } + @Deprecated( "Not needed as {@link com.android.internal.logging.UiEvent} will use #getMetricsSpec", replaceWith = ReplaceWith("getMetricsSpec"), diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java index 9a1ffcbab8d1..3c03d2830327 100644 --- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimDrawable.java @@ -35,6 +35,7 @@ import android.view.animation.DecelerateInterpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import static com.android.systemui.Flags.notificationShadeBlur; /** * Drawable used on SysUI scrims. @@ -213,6 +214,10 @@ public class ScrimDrawable extends Drawable { public void draw(@NonNull Canvas canvas) { mPaint.setColor(mMainColor); mPaint.setAlpha(mAlpha); + if (notificationShadeBlur()) { + // TODO(b/370555223): Match the alpha to the visual spec when it is finalized. + mPaint.setAlpha((int) (0.5f * mAlpha)); + } if (mConcaveInfo != null) { drawConcave(canvas); } else if (mCornerRadiusEnabled && mCornerRadius > 0) { diff --git a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java index 49f3cfc4ceaf..4bfa61e9dcd4 100644 --- a/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java +++ b/packages/SystemUI/src/com/android/systemui/scrim/ScrimView.java @@ -44,6 +44,8 @@ import com.android.systemui.util.LargeScreenUtils; import java.util.concurrent.Executor; +import static com.android.systemui.Flags.notificationShadeBlur; + /** * A view which can draw a scrim. This view maybe be used in multiple windows running on different * threads, but is controlled by {@link com.android.systemui.statusbar.phone.ScrimController} so we @@ -250,6 +252,10 @@ public class ScrimView extends View { if (mBlendWithMainColor) { mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor, tintAmount); } + if (notificationShadeBlur()) { + // TODO(b/370555223): Fix color and transparency to match visual spec exactly + mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), Color.GRAY, 0.5f); + } drawable.setColor(mainTinted, animated); } else { boolean hasAlpha = Color.alpha(mTintColor) != 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt index 6bbd4a504471..d343ed5ab599 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt @@ -35,6 +35,7 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import java.io.PrintWriter import javax.inject.Inject +import com.android.systemui.Flags.notificationShadeBlur @SysUISingleton open class BlurUtils @Inject constructor( @@ -43,7 +44,14 @@ open class BlurUtils @Inject constructor( dumpManager: DumpManager ) : Dumpable { val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius) - val maxBlurRadius = resources.getDimensionPixelSize(R.dimen.max_window_blur_radius) + val maxBlurRadius = + if (notificationShadeBlur()) { + resources.getDimensionPixelSize(R.dimen.max_shade_window_blur_radius) + } else { + resources.getDimensionPixelSize(R.dimen.max_window_blur_radius) + } + + private var lastAppliedBlur = 0 private var earlyWakeupEnabled = false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java index c997ac5ad9df..6fd2d3fafb88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java @@ -768,8 +768,6 @@ public final class KeyboardShortcutListSearch { Intent.CATEGORY_APP_EMAIL, Intent.CATEGORY_APP_CALENDAR, Intent.CATEGORY_APP_MAPS, - Intent.CATEGORY_APP_MUSIC, - Intent.CATEGORY_APP_MESSAGING, Intent.CATEGORY_APP_CALCULATOR, }; String[] shortcutLabels = { @@ -778,19 +776,15 @@ public final class KeyboardShortcutListSearch { mContext.getString(R.string.keyboard_shortcut_group_applications_email), mContext.getString(R.string.keyboard_shortcut_group_applications_calendar), mContext.getString(R.string.keyboard_shortcut_group_applications_maps), - mContext.getString(R.string.keyboard_shortcut_group_applications_music), - mContext.getString(R.string.keyboard_shortcut_group_applications_sms), mContext.getString(R.string.keyboard_shortcut_group_applications_calculator) }; int[] keyCodes = { KeyEvent.KEYCODE_B, - KeyEvent.KEYCODE_C, + KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_E, - KeyEvent.KEYCODE_K, + KeyEvent.KEYCODE_C, KeyEvent.KEYCODE_M, - KeyEvent.KEYCODE_P, - KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_U, }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt index 1db7fb429629..684466ad839b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt @@ -53,6 +53,7 @@ import java.io.PrintWriter import javax.inject.Inject import kotlin.math.max import kotlin.math.sign +import com.android.systemui.Flags.notificationShadeBlur /** * Responsible for blurring the notification shade window, and applying a zoom effect to the @@ -220,7 +221,9 @@ constructor( // Make blur be 0 if it is necessary to stop blur effect. if (scrimsVisible) { - blur = 0 + if (!notificationShadeBlur()) { + blur = 0 + } zoomOut = 0f } @@ -240,7 +243,7 @@ constructor( Choreographer.FrameCallback { updateScheduled = false val (blur, zoomOut) = computeBlurAndZoomOut() - val opaque = scrimsVisible && !blursDisabledForAppLaunch + val opaque = if (notificationShadeBlur()) false else scrimsVisible && !blursDisabledForAppLaunch Trace.traceCounter(Trace.TRACE_TAG_APP, "shade_blur_radius", blur) blurUtils.applyBlur(root.viewRootImpl, blur, opaque) lastAppliedBlur = blur diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt index ef7b1c3d562e..04458f3a7168 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt @@ -14,10 +14,13 @@ * limitations under the License. */ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.statusbar.notification.collection.coordinator import android.app.Notification import android.os.UserHandle +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.keyguard.KeyguardUpdateMonitor import com.android.server.notification.Flags.screenshareNotificationHiding import com.android.systemui.dagger.qualifiers.Application @@ -44,9 +47,9 @@ import dagger.Binds import dagger.Module import javax.inject.Inject import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.mapNotNull -import com.android.app.tracing.coroutines.launchTraced as launch @Module(includes = [PrivateSensitiveContentCoordinatorModule::class]) interface SensitiveContentCoordinatorModule @@ -80,6 +83,7 @@ constructor( DynamicPrivacyController.Listener, OnBeforeRenderListListener { private var inTransitionFromLockedToGone = false + private var canSwipeToEnter = false private val onSensitiveStateChanged = Runnable() { invalidateList("onSensitiveStateChanged") } @@ -98,7 +102,9 @@ constructor( } override fun attach(pipeline: NotifPipeline) { - dynamicPrivacyController.addListener(this) + if (!SceneContainerFlag.isEnabled) { + dynamicPrivacyController.addListener(this) + } if (screenshareNotificationHiding()) { sensitiveNotificationProtectionController.registerSensitiveStateListener( onSensitiveStateChanged @@ -128,6 +134,15 @@ constructor( invalidateList("inTransitionFromLockedToGoneChanged") } } + scope.launch { + deviceEntryInteractor.canSwipeToEnter.collect { + val canSwipeToEnter = it ?: false + if (this@SensitiveContentCoordinatorImpl.canSwipeToEnter != canSwipeToEnter) { + this@SensitiveContentCoordinatorImpl.canSwipeToEnter = canSwipeToEnter + invalidateList("canSwipeToEnterChanged") + } + } + } } } @@ -168,7 +183,9 @@ constructor( (devicePublic && !lockscreenUserManager.userAllowsPrivateNotificationsInPublic(currentUserId)) || isSensitiveContentProtectionActive - val dynamicallyUnlocked = dynamicPrivacyController.isDynamicallyUnlocked + val dynamicallyUnlocked = + if (SceneContainerFlag.isEnabled) canSwipeToEnter + else dynamicPrivacyController.isDynamicallyUnlocked for (entry in extractAllRepresentativeEntries(entries).filter { it.rowExists() }) { val notifUserId = entry.sbn.user.identifier val userLockscreen = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index ba707a5cd0b1..245b1d29fb79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -429,9 +429,10 @@ public class NotificationStackScrollLayoutController implements Dumpable { }; /** - * Recalculate sensitiveness without animation; called when waking up while keyguard occluded. + * Recalculate sensitiveness without animation; called when waking up while keyguard occluded, + * or whenever we update the Lockscreen public mode. */ - public void updateSensitivenessForOccludedWakeup() { + public void updateSensitivenessWithoutAnimation() { updateSensitivenessWithAnimation(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt index d1338eadb6b5..f2ef2f0ab48f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterInternalImpl.kt @@ -313,6 +313,7 @@ constructor( // if it is volume panel. options.setDisallowEnterPictureInPictureWhileLaunching(true) } + intent.collectExtraIntentKeys() try { result[0] = ActivityTaskManager.getService() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index c6af3280eef1..7bea4800f7fc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -2234,6 +2234,9 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // If the state didn't change, we may still need to update public mode mLockscreenUserManager.updatePublicMode(); + if (SceneContainerFlag.isEnabled()) { + mStackScrollerController.updateSensitivenessWithoutAnimation(); + } } if (mStatusBarStateController.leaveOpenOnKeyguardHide()) { if (!mStatusBarStateController.isKeyguardRequested()) { @@ -2681,7 +2684,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // So if AOD is off or unsupported we need to trigger these updates at screen on // when the keyguard is occluded. mLockscreenUserManager.updatePublicMode(); - mStackScrollerController.updateSensitivenessForOccludedWakeup(); + mStackScrollerController.updateSensitivenessWithoutAnimation(); } if (mLaunchCameraWhenFinishedWaking) { startLaunchTransitionTimeout(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt index 1cca3ae0a2c0..d7cc65d22663 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyActivityStarterInternalImpl.kt @@ -180,6 +180,7 @@ constructor( // if it is volume panel. options.setDisallowEnterPictureInPictureWhileLaunching(true) } + intent.collectExtraIntentKeys() try { result[0] = ActivityTaskManager.getService() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt index 08a98c397d5f..12f578c525fd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt @@ -161,6 +161,13 @@ constructor( ) .stateIn(scope, SharingStarted.WhileSubscribed(), true) + /** True if any known mobile network is currently using a non terrestrial network */ + val isAnyConnectionNtn = + iconsInteractor.icons.aggregateOver(selector = { it.isNonTerrestrial }, false) { + nonTerrestrialNetworks -> + nonTerrestrialNetworks.any { it == true } + } + companion object { const val TAG = "DeviceBasedSatelliteInteractor" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt index f3d513940bcf..ea915efb17be 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt @@ -114,34 +114,39 @@ constructor( private val showIcon = if (interactor.isOpportunisticSatelliteIconEnabled) { - canShowIcon - .flatMapLatest { canShow -> - if (!canShow) { - flowOf(false) - } else { - combine( - shouldShowIconForOosAfterHysteresis, - interactor.connectionState, - interactor.isWifiActive, - airplaneModeRepository.isAirplaneMode, - ) { showForOos, connectionState, isWifiActive, isAirplaneMode -> - if (isWifiActive || isAirplaneMode) { - false - } else { - showForOos || - connectionState == SatelliteConnectionState.On || - connectionState == SatelliteConnectionState.Connected + canShowIcon + .flatMapLatest { canShow -> + if (!canShow) { + flowOf(false) + } else { + combine( + shouldShowIconForOosAfterHysteresis, + interactor.isAnyConnectionNtn, + interactor.connectionState, + interactor.isWifiActive, + airplaneModeRepository.isAirplaneMode, + ) { showForOos, anyNtn, connectionState, isWifiActive, isAirplaneMode -> + // anyNtn means that there is some mobile network using ntn, and the + // mobile icon will show its own satellite icon + if (isWifiActive || isAirplaneMode || anyNtn) { + false + } else { + // Show for out of service (which has a hysteresis), or ignore + // the hysteresis if we're already connected + showForOos || + connectionState == SatelliteConnectionState.On || + connectionState == SatelliteConnectionState.Connected + } } } } - } - .distinctUntilChanged() - .logDiffsForTable( - tableLog, - columnPrefix = "vm", - columnName = COL_VISIBLE, - initialValue = false, - ) + .distinctUntilChanged() + .logDiffsForTable( + tableLog, + columnPrefix = "vm", + columnName = COL_VISIBLE, + initialValue = false, + ) } else { flowOf(false) } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractor.kt index b83613ba4f8c..40719185e290 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/domain/VolumeDialogRingerInteractor.kt @@ -20,7 +20,6 @@ import android.media.AudioManager import android.media.AudioManager.RINGER_MODE_NORMAL import android.media.AudioManager.RINGER_MODE_SILENT import android.media.AudioManager.RINGER_MODE_VIBRATE -import android.provider.Settings import com.android.settingslib.volume.data.repository.AudioSystemRepository import com.android.settingslib.volume.shared.model.RingerMode import com.android.systemui.plugins.VolumeDialogController @@ -66,11 +65,6 @@ constructor( } }, currentRingerMode = RingerMode(state.ringerModeInternal), - isEnabled = - !(state.zenMode == Settings.Global.ZEN_MODE_ALARMS || - state.zenMode == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS || - (state.zenMode == Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS && - state.disallowRinger)), isMuted = it.level == 0 || it.muted, level = it.level, levelMax = it.levelMax, diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/shared/model/VolumeDialogRingerModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/shared/model/VolumeDialogRingerModel.kt index 3c24e02f3732..84a82805aace 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/shared/model/VolumeDialogRingerModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/shared/model/VolumeDialogRingerModel.kt @@ -23,8 +23,6 @@ data class VolumeDialogRingerModel( val availableModes: List<RingerMode>, /** Current ringer mode internal */ val currentRingerMode: RingerMode, - /** whether the ringer is allowed given the current ZenMode */ - val isEnabled: Boolean, /** Whether the current ring stream level is zero or the controller state is muted */ val isMuted: Boolean, /** Ring stream level */ 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 3bd2721dcfe5..9eee91beda51 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 @@ -34,6 +34,7 @@ import com.android.settingslib.Utils import com.android.systemui.res.R import com.android.systemui.util.children import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope +import com.android.systemui.volume.dialog.ringer.ui.util.VolumeDialogRingerDrawerTransitionListener import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerButtonUiModel import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerButtonViewModel import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerDrawerState @@ -42,6 +43,7 @@ import com.android.systemui.volume.dialog.ringer.ui.viewmodel.RingerViewModelSta import com.android.systemui.volume.dialog.ringer.ui.viewmodel.VolumeDialogRingerDrawerViewModel import com.android.systemui.volume.dialog.ui.utils.suspendAnimate import javax.inject.Inject +import kotlin.properties.Delegates import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.launchIn @@ -71,6 +73,27 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { val drawerContainer = view.requireViewById<MotionLayout>(R.id.volume_ringer_drawer) val unselectedButtonUiModel = RingerButtonUiModel.getUnselectedButton(view.context) val selectedButtonUiModel = RingerButtonUiModel.getSelectedButton(view.context) + val volumeDialogBgSmallRadius = + view.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_background_square_corner_radius + ) + val volumeDialogBgFullRadius = + view.context.resources.getDimensionPixelSize( + R.dimen.volume_dialog_background_corner_radius + ) + var backgroundAnimationProgress: Float by + Delegates.observable(0F) { _, _, progress -> + volumeDialogBackgroundView.applyCorners( + fullRadius = volumeDialogBgFullRadius, + diff = volumeDialogBgFullRadius - volumeDialogBgSmallRadius, + progress, + ) + } + val ringerDrawerTransitionListener = VolumeDialogRingerDrawerTransitionListener { + backgroundAnimationProgress = it + } + drawerContainer.setTransitionListener(ringerDrawerTransitionListener) + volumeDialogBackgroundView.background = volumeDialogBackgroundView.background.mutate() viewModel.ringerViewModel .onEach { ringerState -> when (ringerState) { @@ -87,10 +110,8 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { selectedButtonUiModel, unselectedButtonUiModel, ) + ringerDrawerTransitionListener.setProgressChangeEnabled(true) drawerContainer.closeDrawer(uiModel.currentButtonIndex) - volumeDialogBackgroundView.setBackgroundResource( - R.drawable.volume_dialog_background - ) } is RingerDrawerState.Closed -> { @@ -103,11 +124,31 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { uiModel, selectedButtonUiModel, unselectedButtonUiModel, + onProgressChanged = { progress, isReverse -> + // Let's make button progress when switching matches + // motionLayout transition progress. When full radius, + // progress is 0.0. When small radius, progress is 1.0. + backgroundAnimationProgress = + if (isReverse) { + 1F - progress + } else { + progress + } + }, ) { + if ( + uiModel.currentButtonIndex == + uiModel.availableButtons.size - 1 + ) { + ringerDrawerTransitionListener.setProgressChangeEnabled( + false + ) + } else { + ringerDrawerTransitionListener.setProgressChangeEnabled( + true + ) + } drawerContainer.closeDrawer(uiModel.currentButtonIndex) - volumeDialogBackgroundView.setBackgroundResource( - R.drawable.volume_dialog_background - ) } } } @@ -120,16 +161,18 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { unselectedButtonUiModel, ) // Open drawer - drawerContainer.transitionToState( - R.id.volume_dialog_ringer_drawer_open - ) if ( - uiModel.currentButtonIndex != uiModel.availableButtons.size - 1 + uiModel.currentButtonIndex == uiModel.availableButtons.size - 1 ) { - volumeDialogBackgroundView.setBackgroundResource( - R.drawable.volume_dialog_background_small_radius - ) + ringerDrawerTransitionListener.setProgressChangeEnabled(false) + } else { + ringerDrawerTransitionListener.setProgressChangeEnabled(true) } + drawerContainer.transitionToState( + R.id.volume_dialog_ringer_drawer_open + ) + volumeDialogBackgroundView.background = + volumeDialogBackgroundView.background.mutate() } } } @@ -150,6 +193,7 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { uiModel: RingerViewModel, selectedButtonUiModel: RingerButtonUiModel, unselectedButtonUiModel: RingerButtonUiModel, + onProgressChanged: (Float, Boolean) -> Unit = { _, _ -> }, onAnimationEnd: Runnable? = null, ) { ensureChildCount(R.layout.volume_ringer_button, uiModel.availableButtons.size) @@ -177,10 +221,26 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { CLOSE_DRAWER_DELAY, ) } - - // We only need to execute on roundness animation end once. - selectedButton.animateTo(selectedButtonUiModel, roundnessAnimationEndListener) - unselectedButton.animateTo(unselectedButtonUiModel) + // We only need to execute on roundness animation end and volume dialog background + // progress update once because these changes should be applied once on volume dialog + // background and ringer drawer views. + selectedButton.animateTo( + selectedButtonUiModel, + if (uiModel.currentButtonIndex == count - 1) { + onProgressChanged + } else { + { _, _ -> } + }, + roundnessAnimationEndListener, + ) + unselectedButton.animateTo( + unselectedButtonUiModel, + if (previousIndex == count - 1) { + onProgressChanged + } else { + { _, _ -> } + }, + ) } else { bindButtons(viewModel, uiModel, onAnimationEnd) } @@ -366,6 +426,7 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { private suspend fun ImageButton.animateTo( ringerButtonUiModel: RingerButtonUiModel, + onProgressChanged: (Float, Boolean) -> Unit = { _, _ -> }, roundnessAnimationEndListener: DynamicAnimation.OnAnimationEndListener? = null, ) { val roundnessAnimation = @@ -376,6 +437,7 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { ringerButtonUiModel.cornerRadius - (background as GradientDrawable).cornerRadius val roundnessAnimationUpdateListener = DynamicAnimation.OnAnimationUpdateListener { _, value, _ -> + onProgressChanged(value, cornerRadiusDiff > 0F) (background as GradientDrawable).cornerRadius = radius + value * cornerRadiusDiff background.invalidateSelf() } @@ -406,4 +468,9 @@ constructor(private val viewModel: VolumeDialogRingerDrawerViewModel) { ) } } + + private fun View.applyCorners(fullRadius: Int, diff: Int, progress: Float) { + (background as GradientDrawable).cornerRadius = fullRadius - progress * diff + background.invalidateSelf() + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/VolumeDialogRingerDrawerTransitionListener.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/VolumeDialogRingerDrawerTransitionListener.kt new file mode 100644 index 000000000000..6e3db0afb483 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/util/VolumeDialogRingerDrawerTransitionListener.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.dialog.ringer.ui.util + +import androidx.constraintlayout.motion.widget.MotionLayout + +class VolumeDialogRingerDrawerTransitionListener(private val onProgressChanged: (Float) -> Unit) : + MotionLayout.TransitionListener { + + private var notifyProgressChangeEnabled = true + + fun setProgressChangeEnabled(enabled: Boolean) { + notifyProgressChangeEnabled = enabled + } + + override fun onTransitionStarted(motionLayout: MotionLayout?, startId: Int, endId: Int) {} + + override fun onTransitionChange( + motionLayout: MotionLayout?, + startId: Int, + endId: Int, + progress: Float, + ) { + if (notifyProgressChangeEnabled) { + onProgressChanged(progress) + } + } + + override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {} + + override fun onTransitionTrigger( + motionLayout: MotionLayout?, + triggerId: Int, + positive: Boolean, + progress: Float, + ) {} +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt index e646636dd2a2..627d75ee108d 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModel.kt @@ -21,10 +21,13 @@ import android.media.AudioAttributes import android.media.AudioManager.RINGER_MODE_NORMAL import android.media.AudioManager.RINGER_MODE_SILENT import android.media.AudioManager.RINGER_MODE_VIBRATE +import android.media.AudioManager.STREAM_RING import android.os.VibrationEffect import android.widget.Toast import com.android.internal.R as internalR import com.android.settingslib.Utils +import com.android.settingslib.notification.domain.interactor.NotificationsSoundPolicyInteractor +import com.android.settingslib.volume.shared.model.AudioStream import com.android.settingslib.volume.shared.model.RingerMode import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background @@ -57,7 +60,8 @@ constructor( @Application private val applicationContext: Context, @VolumeDialog private val coroutineScope: CoroutineScope, @Background private val backgroundDispatcher: CoroutineDispatcher, - private val interactor: VolumeDialogRingerInteractor, + soundPolicyInteractor: NotificationsSoundPolicyInteractor, + private val ringerInteractor: VolumeDialogRingerInteractor, private val vibrator: VibratorHelper, private val volumeDialogLogger: VolumeDialogLogger, private val visibilityInteractor: VolumeDialogVisibilityInteractor, @@ -66,10 +70,14 @@ constructor( private val drawerState = MutableStateFlow<RingerDrawerState>(RingerDrawerState.Initial) val ringerViewModel: StateFlow<RingerViewModelState> = - combine(interactor.ringerModel, drawerState) { ringerModel, state -> + combine( + soundPolicyInteractor.isZenMuted(AudioStream(STREAM_RING)), + ringerInteractor.ringerModel, + drawerState, + ) { isZenMuted, ringerModel, state -> level = ringerModel.level levelMax = ringerModel.levelMax - ringerModel.toViewModel(state) + ringerModel.toViewModel(state, isZenMuted) } .flowOn(backgroundDispatcher) .stateIn(coroutineScope, SharingStarted.Eagerly, RingerViewModelState.Unavailable) @@ -90,7 +98,7 @@ constructor( Events.writeEvent(Events.EVENT_RINGER_TOGGLE, ringerMode.value) provideTouchFeedback(ringerMode) maybeShowToast(ringerMode) - interactor.setRingerMode(ringerMode) + ringerInteractor.setRingerMode(ringerMode) } visibilityInteractor.resetDismissTimeout() drawerState.value = @@ -113,7 +121,7 @@ constructor( private fun provideTouchFeedback(ringerMode: RingerMode) { when (ringerMode.value) { RINGER_MODE_NORMAL -> { - interactor.scheduleTouchFeedback() + ringerInteractor.scheduleTouchFeedback() null } RINGER_MODE_SILENT -> VibrationEffect.get(VibrationEffect.EFFECT_CLICK) @@ -123,7 +131,8 @@ constructor( } private fun VolumeDialogRingerModel.toViewModel( - drawerState: RingerDrawerState + drawerState: RingerDrawerState, + isZenMuted: Boolean, ): RingerViewModelState { val currentIndex = availableModes.indexOf(currentRingerMode) if (currentIndex == -1) { @@ -132,10 +141,11 @@ constructor( return if (currentIndex == -1 || isSingleVolume) { RingerViewModelState.Unavailable } else { - toButtonViewModel(currentRingerMode, isSelectedButton = true)?.let { + toButtonViewModel(currentRingerMode, isZenMuted, isSelectedButton = true)?.let { RingerViewModelState.Available( RingerViewModel( - availableButtons = availableModes.map { mode -> toButtonViewModel(mode) }, + availableButtons = + availableModes.map { mode -> toButtonViewModel(mode, isZenMuted) }, currentButtonIndex = currentIndex, selectedButton = it, drawerState = drawerState, @@ -147,6 +157,7 @@ constructor( private fun VolumeDialogRingerModel.toButtonViewModel( ringerMode: RingerMode, + isZenMuted: Boolean, isSelectedButton: Boolean = false, ): RingerButtonViewModel? { return when (ringerMode.value) { @@ -176,7 +187,7 @@ constructor( ) RINGER_MODE_NORMAL -> when { - isMuted && isEnabled -> + isMuted && !isZenMuted -> RingerButtonViewModel( imageResId = if (isSelectedButton) { @@ -226,7 +237,7 @@ constructor( private fun maybeShowToast(ringerMode: RingerMode) { coroutineScope.launch { - val seenToastCount = interactor.getToastCount() + val seenToastCount = ringerInteractor.getToastCount() if (seenToastCount > SHOW_RINGER_TOAST_COUNT) { return@launch } @@ -260,7 +271,7 @@ constructor( ) } toastText?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT).show() } - interactor.updateToastCount(seenToastCount) + ringerInteractor.updateToastCount(seenToastCount) } } } 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 e52bad9c39bf..f30524638150 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 @@ -18,11 +18,12 @@ package com.android.systemui.volume.dialog.sliders.ui import android.animation.Animator import android.animation.ObjectAnimator +import android.annotation.SuppressLint import android.view.View import android.view.animation.DecelerateInterpolator import com.android.systemui.res.R -import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope +import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderStateModel import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory import com.android.systemui.volume.dialog.ui.utils.awaitAnimation @@ -48,24 +49,27 @@ constructor( val sliderView: Slider = view.requireViewById<Slider>(R.id.volume_dialog_slider).apply { labelBehavior = LabelFormatter.LABEL_GONE + trackIconActiveColor = trackInactiveTintList } sliderView.addOnChangeListener { _, value, fromUser -> viewModel.setStreamVolume(value.roundToInt(), fromUser) } - viewModel.model.onEach { it.bindToSlider(sliderView) }.launchIn(this) + viewModel.state.onEach { it.bindToSlider(sliderView) }.launchIn(this) } - private suspend fun VolumeDialogStreamModel.bindToSlider(slider: Slider) { + @SuppressLint("UseCompatLoadingForDrawables") + private suspend fun VolumeDialogSliderStateModel.bindToSlider(slider: Slider) { with(slider) { - valueFrom = levelMin.toFloat() - valueTo = levelMax.toFloat() + valueFrom = minValue + valueTo = maxValue // coerce the current value to the new value range before animating it value = value.coerceIn(valueFrom, valueTo) setValueAnimated( - level.toFloat(), + value, jankListenerFactory.update(this, PROGRESS_CHANGE_ANIMATION_DURATION_MS), ) + trackIconActiveEnd = context.getDrawable(iconRes) } } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt new file mode 100644 index 000000000000..5c39b6f9359c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderIconProvider.kt @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.dialog.sliders.ui.viewmodel + +import android.media.AudioManager +import androidx.annotation.DrawableRes +import com.android.settingslib.notification.domain.interactor.NotificationsSoundPolicyInteractor +import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor +import com.android.settingslib.volume.shared.model.AudioStream +import com.android.settingslib.volume.shared.model.RingerMode +import com.android.systemui.res.R +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOf + +class VolumeDialogSliderIconProvider +@Inject +constructor( + private val notificationsSoundPolicyInteractor: NotificationsSoundPolicyInteractor, + private val audioVolumeInteractor: AudioVolumeInteractor, +) { + + @DrawableRes + fun getStreamIcon( + stream: Int, + level: Int, + levelMin: Int, + levelMax: Int, + isMuted: Boolean, + isRoutedToBluetooth: Boolean, + ): Flow<Int> { + return combine( + notificationsSoundPolicyInteractor.isZenMuted(AudioStream(stream)), + ringerModeForStream(stream), + ) { isZenMuted, ringerMode -> + val isStreamOffline = level == 0 || isMuted + if (isZenMuted) { + // TODO(b/372466264) use icon for the corresponding zenmode + return@combine com.android.internal.R.drawable.ic_qs_dnd + } + when (ringerMode?.value) { + AudioManager.RINGER_MODE_VIBRATE -> + return@combine R.drawable.ic_volume_ringer_vibrate + AudioManager.RINGER_MODE_SILENT -> return@combine R.drawable.ic_ring_volume_off + } + if (isRoutedToBluetooth) { + return@combine if (stream == AudioManager.STREAM_VOICE_CALL) { + R.drawable.ic_volume_bt_sco + } else { + if (isStreamOffline) { + R.drawable.ic_volume_media_bt_mute + } else { + R.drawable.ic_volume_media_bt + } + } + } + + return@combine if (isStreamOffline) { + getMutedIconForStream(stream) ?: getIconForStream(stream) + } else { + if (level < (levelMax + levelMin) / 2) { + // This icon is different on TV + R.drawable.ic_volume_media_low + } else { + getIconForStream(stream) + } + } + } + } + + @DrawableRes + private fun getMutedIconForStream(stream: Int): Int? { + return when (stream) { + AudioManager.STREAM_MUSIC -> R.drawable.ic_volume_media_mute + AudioManager.STREAM_NOTIFICATION -> R.drawable.ic_volume_ringer_mute + AudioManager.STREAM_ALARM -> R.drawable.ic_volume_alarm_mute + AudioManager.STREAM_SYSTEM -> R.drawable.ic_volume_system_mute + else -> null + } + } + + @DrawableRes + private fun getIconForStream(stream: Int): Int { + return when (stream) { + AudioManager.STREAM_ACCESSIBILITY -> R.drawable.ic_volume_accessibility + AudioManager.STREAM_MUSIC -> R.drawable.ic_volume_media + AudioManager.STREAM_RING -> R.drawable.ic_ring_volume + AudioManager.STREAM_NOTIFICATION -> R.drawable.ic_volume_ringer + AudioManager.STREAM_ALARM -> R.drawable.ic_alarm + AudioManager.STREAM_VOICE_CALL -> com.android.internal.R.drawable.ic_phone + AudioManager.STREAM_SYSTEM -> R.drawable.ic_volume_system + else -> error("Unsupported stream: $stream") + } + } + + /** + * Emits [RingerMode] for the [stream] if it's affecting it and null when [RingerMode] doesn't + * affect the [stream] + */ + private fun ringerModeForStream(stream: Int): Flow<RingerMode?> { + return if (stream == AudioManager.STREAM_RING) { + audioVolumeInteractor.ringerMode + } else { + flowOf(null) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderStateModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderStateModel.kt new file mode 100644 index 000000000000..5750c049082f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderStateModel.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.dialog.sliders.ui.viewmodel + +import androidx.annotation.DrawableRes +import com.android.systemui.volume.dialog.shared.model.VolumeDialogStreamModel + +data class VolumeDialogSliderStateModel( + val minValue: Float, + val maxValue: Float, + val value: Float, + @DrawableRes val iconRes: Int, +) + +fun VolumeDialogStreamModel.toStateModel(@DrawableRes iconRes: Int): VolumeDialogSliderStateModel { + return VolumeDialogSliderStateModel( + minValue = levelMin.toFloat(), + value = level.toFloat(), + maxValue = levelMax.toFloat(), + iconRes = iconRes, + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt index 6dd5b638a3bc..2d5652420ec8 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/viewmodel/VolumeDialogSliderViewModel.kt @@ -32,7 +32,9 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.stateIn @@ -56,12 +58,12 @@ constructor( private val interactor: VolumeDialogSliderInteractor, private val visibilityInteractor: VolumeDialogVisibilityInteractor, @VolumeDialog private val coroutineScope: CoroutineScope, + private val volumeDialogSliderIconProvider: VolumeDialogSliderIconProvider, private val systemClock: SystemClock, ) { private val userVolumeUpdates = MutableStateFlow<VolumeUpdate?>(null) - - val model: Flow<VolumeDialogStreamModel> = + private val model: Flow<VolumeDialogStreamModel> = interactor.slider .filter { val lastVolumeUpdateTime = userVolumeUpdates.value?.timestampMillis ?: 0 @@ -70,6 +72,21 @@ constructor( .stateIn(coroutineScope, SharingStarted.Eagerly, null) .filterNotNull() + val state: Flow<VolumeDialogSliderStateModel> = + model.flatMapLatest { streamModel -> + with(streamModel) { + volumeDialogSliderIconProvider.getStreamIcon( + stream = stream, + level = level, + levelMin = levelMin, + levelMax = levelMax, + isMuted = muted, + isRoutedToBluetooth = routedToBluetooth, + ) + } + .map { icon -> streamModel.toStateModel(icon) } + } + init { userVolumeUpdates .filterNotNull() diff --git a/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorParameterizedTest.kt new file mode 100644 index 000000000000..d7fcb6a4c2a7 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorParameterizedTest.kt @@ -0,0 +1,471 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.education.domain.interactor + +import android.content.pm.UserInfo +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.contextualeducation.GestureType +import com.android.systemui.contextualeducation.GestureType.ALL_APPS +import com.android.systemui.contextualeducation.GestureType.BACK +import com.android.systemui.contextualeducation.GestureType.HOME +import com.android.systemui.contextualeducation.GestureType.OVERVIEW +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.coroutines.collectValues +import com.android.systemui.education.data.model.GestureEduModel +import com.android.systemui.education.data.repository.contextualEducationRepository +import com.android.systemui.education.data.repository.fakeEduClock +import com.android.systemui.education.shared.model.EducationUiType +import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType +import com.android.systemui.inputdevice.tutorial.tutorialSchedulerRepository +import com.android.systemui.keyboard.data.repository.keyboardRepository +import com.android.systemui.kosmos.testScope +import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener +import com.android.systemui.testKosmos +import com.android.systemui.touchpad.data.repository.touchpadRepository +import com.android.systemui.user.data.repository.fakeUserRepository +import com.google.common.truth.Truth.assertThat +import kotlin.time.Duration.Companion.hours +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.After +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.verify +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters + +@SmallTest +@RunWith(ParameterizedAndroidJunit4::class) +@kotlinx.coroutines.ExperimentalCoroutinesApi +class KeyboardTouchpadEduInteractorParameterizedTest(private val gestureType: GestureType) : + SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val contextualEduInteractor = kosmos.contextualEducationInteractor + private val repository = kosmos.contextualEducationRepository + private val touchpadRepository = kosmos.touchpadRepository + private val keyboardRepository = kosmos.keyboardRepository + private val tutorialSchedulerRepository = kosmos.tutorialSchedulerRepository + private val userRepository = kosmos.fakeUserRepository + private val overviewProxyService = kosmos.mockOverviewProxyService + + private val underTest: KeyboardTouchpadEduInteractor = kosmos.keyboardTouchpadEduInteractor + private val eduClock = kosmos.fakeEduClock + private val minDurationForNextEdu = + KeyboardTouchpadEduInteractor.minIntervalBetweenEdu + 1.seconds + private val initialDelayElapsedDuration = + KeyboardTouchpadEduInteractor.initialDelayDuration + 1.seconds + + @Before + fun setup() { + underTest.start() + contextualEduInteractor.start() + userRepository.setUserInfos(USER_INFOS) + testScope.launch { + contextualEduInteractor.updateKeyboardFirstConnectionTime() + contextualEduInteractor.updateTouchpadFirstConnectionTime() + } + } + + @Test + fun newEducationInfoOnMaxSignalCountReached() = + testScope.runTest { + triggerMaxEducationSignals(gestureType) + val model by collectLastValue(underTest.educationTriggered) + + assertThat(model?.gestureType).isEqualTo(gestureType) + } + + @Test + fun newEducationToastOn1stEducation() = + testScope.runTest { + val model by collectLastValue(underTest.educationTriggered) + triggerMaxEducationSignals(gestureType) + + assertThat(model?.educationUiType).isEqualTo(EducationUiType.Toast) + } + + @Test + fun newEducationNotificationOn2ndEducation() = + testScope.runTest { + val model by collectLastValue(underTest.educationTriggered) + triggerMaxEducationSignals(gestureType) + // runCurrent() to trigger 1st education + runCurrent() + + eduClock.offset(minDurationForNextEdu) + triggerMaxEducationSignals(gestureType) + + assertThat(model?.educationUiType).isEqualTo(EducationUiType.Notification) + } + + @Test + fun noEducationInfoBeforeMaxSignalCountReached() = + testScope.runTest { + contextualEduInteractor.incrementSignalCount(gestureType) + val model by collectLastValue(underTest.educationTriggered) + assertThat(model).isNull() + } + + @Test + fun noEducationInfoWhenShortcutTriggeredPreviously() = + testScope.runTest { + val model by collectLastValue(underTest.educationTriggered) + contextualEduInteractor.updateShortcutTriggerTime(gestureType) + triggerMaxEducationSignals(gestureType) + assertThat(model).isNull() + } + + @Test + fun no2ndEducationBeforeMinEduIntervalReached() = + testScope.runTest { + val models by collectValues(underTest.educationTriggered) + triggerMaxEducationSignals(gestureType) + runCurrent() + + // Offset a duration that is less than the required education interval + eduClock.offset(1.seconds) + triggerMaxEducationSignals(gestureType) + runCurrent() + + assertThat(models.filterNotNull().size).isEqualTo(1) + } + + @Test + fun noNewEducationInfoAfterMaxEducationCountReached() = + testScope.runTest { + val models by collectValues(underTest.educationTriggered) + // Trigger 2 educations + triggerMaxEducationSignals(gestureType) + runCurrent() + eduClock.offset(minDurationForNextEdu) + triggerMaxEducationSignals(gestureType) + runCurrent() + + // Try triggering 3rd education + eduClock.offset(minDurationForNextEdu) + triggerMaxEducationSignals(gestureType) + + assertThat(models.filterNotNull().size).isEqualTo(2) + } + + @Test + fun startNewUsageSessionWhen2ndSignalReceivedAfterSessionDeadline() = + testScope.runTest { + val model by + collectLastValue( + kosmos.contextualEducationRepository.readGestureEduModelFlow(gestureType) + ) + contextualEduInteractor.incrementSignalCount(gestureType) + eduClock.offset(KeyboardTouchpadEduInteractor.usageSessionDuration.plus(1.seconds)) + val secondSignalReceivedTime = eduClock.instant() + contextualEduInteractor.incrementSignalCount(gestureType) + + assertThat(model) + .isEqualTo( + GestureEduModel( + signalCount = 1, + usageSessionStartTime = secondSignalReceivedTime, + userId = 0, + gestureType = gestureType, + ) + ) + } + + @Test + fun newTouchpadConnectionTimeOnFirstTouchpadConnected() = + testScope.runTest { + setIsAnyTouchpadConnected(true) + val model = contextualEduInteractor.getEduDeviceConnectionTime() + assertThat(model.touchpadFirstConnectionTime).isEqualTo(eduClock.instant()) + } + + @Test + fun unchangedTouchpadConnectionTimeOnSecondConnection() = + testScope.runTest { + val firstConnectionTime = eduClock.instant() + setIsAnyTouchpadConnected(true) + setIsAnyTouchpadConnected(false) + + eduClock.offset(1.hours) + setIsAnyTouchpadConnected(true) + + val model = contextualEduInteractor.getEduDeviceConnectionTime() + assertThat(model.touchpadFirstConnectionTime).isEqualTo(firstConnectionTime) + } + + @Test + fun newTouchpadConnectionTimeOnUserChanged() = + testScope.runTest { + // Touchpad connected for user 0 + setIsAnyTouchpadConnected(true) + + // Change user + eduClock.offset(1.hours) + val newUserFirstConnectionTime = eduClock.instant() + userRepository.setSelectedUserInfo(USER_INFOS[0]) + runCurrent() + + val model = contextualEduInteractor.getEduDeviceConnectionTime() + assertThat(model.touchpadFirstConnectionTime).isEqualTo(newUserFirstConnectionTime) + } + + @Test + fun newKeyboardConnectionTimeOnKeyboardConnected() = + testScope.runTest { + setIsAnyKeyboardConnected(true) + val model = contextualEduInteractor.getEduDeviceConnectionTime() + assertThat(model.keyboardFirstConnectionTime).isEqualTo(eduClock.instant()) + } + + @Test + fun unchangedKeyboardConnectionTimeOnSecondConnection() = + testScope.runTest { + val firstConnectionTime = eduClock.instant() + setIsAnyKeyboardConnected(true) + setIsAnyKeyboardConnected(false) + + eduClock.offset(1.hours) + setIsAnyKeyboardConnected(true) + + val model = contextualEduInteractor.getEduDeviceConnectionTime() + assertThat(model.keyboardFirstConnectionTime).isEqualTo(firstConnectionTime) + } + + @Test + fun newKeyboardConnectionTimeOnUserChanged() = + testScope.runTest { + // Keyboard connected for user 0 + setIsAnyKeyboardConnected(true) + + // Change user + eduClock.offset(1.hours) + val newUserFirstConnectionTime = eduClock.instant() + userRepository.setSelectedUserInfo(USER_INFOS[0]) + runCurrent() + + val model = contextualEduInteractor.getEduDeviceConnectionTime() + assertThat(model.keyboardFirstConnectionTime).isEqualTo(newUserFirstConnectionTime) + } + + @Test + fun updateShortcutTimeOnKeyboardShortcutTriggered() = + testScope.runTest { + // Only All Apps needs to update the keyboard shortcut + assumeTrue(gestureType == ALL_APPS) + kosmos.contextualEducationRepository.setKeyboardShortcutTriggered(ALL_APPS) + + val model by + collectLastValue( + kosmos.contextualEducationRepository.readGestureEduModelFlow(ALL_APPS) + ) + assertThat(model?.lastShortcutTriggeredTime).isEqualTo(eduClock.instant()) + } + + @Test + fun dataUpdatedOnIncrementSignalCountWhenTouchpadConnected() = + testScope.runTest { + assumeTrue(gestureType != ALL_APPS) + setUpForInitialDelayElapse() + touchpadRepository.setIsAnyTouchpadConnected(true) + + val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) + val originalValue = model!!.signalCount + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + + assertThat(model?.signalCount).isEqualTo(originalValue + 1) + } + + @Test + fun dataUnchangedOnIncrementSignalCountWhenTouchpadDisconnected() = + testScope.runTest { + setUpForInitialDelayElapse() + touchpadRepository.setIsAnyTouchpadConnected(false) + + val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) + val originalValue = model!!.signalCount + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + + assertThat(model?.signalCount).isEqualTo(originalValue) + } + + @Test + fun dataUpdatedOnIncrementSignalCountWhenKeyboardConnected() = + testScope.runTest { + assumeTrue(gestureType == ALL_APPS) + setUpForInitialDelayElapse() + keyboardRepository.setIsAnyKeyboardConnected(true) + + val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) + val originalValue = model!!.signalCount + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + + assertThat(model?.signalCount).isEqualTo(originalValue + 1) + } + + @Test + fun dataUnchangedOnIncrementSignalCountWhenKeyboardDisconnected() = + testScope.runTest { + setUpForInitialDelayElapse() + keyboardRepository.setIsAnyKeyboardConnected(false) + + val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) + val originalValue = model!!.signalCount + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + + assertThat(model?.signalCount).isEqualTo(originalValue) + } + + @Test + fun dataAddedOnUpdateShortcutTriggerTime() = + testScope.runTest { + val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) + assertThat(model?.lastShortcutTriggeredTime).isNull() + + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ true, gestureType) + + assertThat(model?.lastShortcutTriggeredTime).isEqualTo(kosmos.fakeEduClock.instant()) + } + + @Test + fun dataUpdatedOnIncrementSignalCountAfterInitialDelay() = + testScope.runTest { + setUpForDeviceConnection() + tutorialSchedulerRepository.updateLaunchTime(DeviceType.TOUCHPAD, eduClock.instant()) + + val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) + val originalValue = model!!.signalCount + eduClock.offset(initialDelayElapsedDuration) + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + + assertThat(model?.signalCount).isEqualTo(originalValue + 1) + } + + @Test + fun dataUnchangedOnIncrementSignalCountBeforeInitialDelay() = + testScope.runTest { + setUpForDeviceConnection() + tutorialSchedulerRepository.updateLaunchTime(DeviceType.TOUCHPAD, eduClock.instant()) + + val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) + val originalValue = model!!.signalCount + // No offset to the clock to simulate update before initial delay + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + + assertThat(model?.signalCount).isEqualTo(originalValue) + } + + @Test + fun dataUnchangedOnIncrementSignalCountWithoutOobeLaunchTime() = + testScope.runTest { + // No update to OOBE launch time to simulate no OOBE is launched yet + setUpForDeviceConnection() + + val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) + val originalValue = model!!.signalCount + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + + assertThat(model?.signalCount).isEqualTo(originalValue) + } + + private suspend fun setUpForInitialDelayElapse() { + tutorialSchedulerRepository.updateLaunchTime(DeviceType.TOUCHPAD, eduClock.instant()) + tutorialSchedulerRepository.updateLaunchTime(DeviceType.KEYBOARD, eduClock.instant()) + eduClock.offset(initialDelayElapsedDuration) + } + + fun logMetricsForToastEducation() = + testScope.runTest { + triggerMaxEducationSignals(gestureType) + runCurrent() + + verify(kosmos.mockEduMetricsLogger) + .logContextualEducationTriggered(gestureType, EducationUiType.Toast) + } + + @Test + fun logMetricsForNotificationEducation() = + testScope.runTest { + triggerMaxEducationSignals(gestureType) + runCurrent() + + eduClock.offset(minDurationForNextEdu) + triggerMaxEducationSignals(gestureType) + runCurrent() + + verify(kosmos.mockEduMetricsLogger) + .logContextualEducationTriggered(gestureType, EducationUiType.Notification) + } + + @After + fun clear() { + testScope.launch { tutorialSchedulerRepository.clear() } + } + + private suspend fun triggerMaxEducationSignals(gestureType: GestureType) { + // Increment max number of signal to try triggering education + for (i in 1..KeyboardTouchpadEduInteractor.MAX_SIGNAL_COUNT) { + contextualEduInteractor.incrementSignalCount(gestureType) + } + } + + private fun TestScope.setIsAnyTouchpadConnected(isConnected: Boolean) { + touchpadRepository.setIsAnyTouchpadConnected(isConnected) + runCurrent() + } + + private fun TestScope.setIsAnyKeyboardConnected(isConnected: Boolean) { + keyboardRepository.setIsAnyKeyboardConnected(isConnected) + runCurrent() + } + + private fun setUpForDeviceConnection() { + touchpadRepository.setIsAnyTouchpadConnected(true) + keyboardRepository.setIsAnyKeyboardConnected(true) + } + + private fun getOverviewProxyListener(): OverviewProxyListener { + val listenerCaptor = argumentCaptor<OverviewProxyListener>() + verify(overviewProxyService).addCallback(listenerCaptor.capture()) + return listenerCaptor.firstValue + } + + companion object { + private val USER_INFOS = listOf(UserInfo(101, "Second User", 0)) + + @JvmStatic + @Parameters(name = "{0}") + fun getGestureTypes(): List<GestureType> { + return listOf(BACK, HOME, OVERVIEW, ALL_APPS) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt index 2a6d29c61890..580f631734e7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/education/domain/interactor/KeyboardTouchpadEduInteractorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2024 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,17 @@ package com.android.systemui.education.domain.interactor -import android.content.pm.UserInfo +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.contextualeducation.GestureType -import com.android.systemui.contextualeducation.GestureType.ALL_APPS import com.android.systemui.contextualeducation.GestureType.BACK import com.android.systemui.contextualeducation.GestureType.HOME import com.android.systemui.contextualeducation.GestureType.OVERVIEW import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues -import com.android.systemui.education.data.model.GestureEduModel -import com.android.systemui.education.data.repository.contextualEducationRepository import com.android.systemui.education.data.repository.fakeEduClock +import com.android.systemui.education.shared.model.EducationInfo import com.android.systemui.education.shared.model.EducationUiType import com.android.systemui.inputdevice.tutorial.data.repository.DeviceType import com.android.systemui.inputdevice.tutorial.tutorialSchedulerRepository @@ -37,50 +35,42 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener import com.android.systemui.testKosmos import com.android.systemui.touchpad.data.repository.touchpadRepository -import com.android.systemui.user.data.repository.fakeUserRepository import com.google.common.truth.Truth.assertThat -import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.launch import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest -import org.junit.After -import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.verify -import platform.test.runner.parameterized.ParameterizedAndroidJunit4 -import platform.test.runner.parameterized.Parameters @SmallTest -@RunWith(ParameterizedAndroidJunit4::class) +@RunWith(AndroidJUnit4::class) @kotlinx.coroutines.ExperimentalCoroutinesApi -class KeyboardTouchpadEduInteractorTest(private val gestureType: GestureType) : SysuiTestCase() { +class KeyboardTouchpadEduInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val contextualEduInteractor = kosmos.contextualEducationInteractor - private val repository = kosmos.contextualEducationRepository private val touchpadRepository = kosmos.touchpadRepository private val keyboardRepository = kosmos.keyboardRepository private val tutorialSchedulerRepository = kosmos.tutorialSchedulerRepository - private val userRepository = kosmos.fakeUserRepository private val overviewProxyService = kosmos.mockOverviewProxyService private val underTest: KeyboardTouchpadEduInteractor = kosmos.keyboardTouchpadEduInteractor private val eduClock = kosmos.fakeEduClock - private val minDurationForNextEdu = - KeyboardTouchpadEduInteractor.minIntervalBetweenEdu + 1.seconds private val initialDelayElapsedDuration = KeyboardTouchpadEduInteractor.initialDelayDuration + 1.seconds + private val minIntervalForEduNotification = + KeyboardTouchpadEduInteractor.minIntervalBetweenEdu + 1.seconds @Before fun setup() { underTest.start() contextualEduInteractor.start() - userRepository.setUserInfos(USER_INFOS) testScope.launch { contextualEduInteractor.updateKeyboardFirstConnectionTime() contextualEduInteractor.updateTouchpadFirstConnectionTime() @@ -88,312 +78,76 @@ class KeyboardTouchpadEduInteractorTest(private val gestureType: GestureType) : } @Test - fun newEducationInfoOnMaxSignalCountReached() = - testScope.runTest { - triggerMaxEducationSignals(gestureType) - val model by collectLastValue(underTest.educationTriggered) - - assertThat(model?.gestureType).isEqualTo(gestureType) - } - - @Test - fun newEducationToastOn1stEducation() = - testScope.runTest { - val model by collectLastValue(underTest.educationTriggered) - triggerMaxEducationSignals(gestureType) - - assertThat(model?.educationUiType).isEqualTo(EducationUiType.Toast) - } - - @Test - fun newEducationNotificationOn2ndEducation() = - testScope.runTest { - val model by collectLastValue(underTest.educationTriggered) - triggerMaxEducationSignals(gestureType) - // runCurrent() to trigger 1st education - runCurrent() - - eduClock.offset(minDurationForNextEdu) - triggerMaxEducationSignals(gestureType) - - assertThat(model?.educationUiType).isEqualTo(EducationUiType.Notification) - } - - @Test - fun noEducationInfoBeforeMaxSignalCountReached() = - testScope.runTest { - contextualEduInteractor.incrementSignalCount(gestureType) - val model by collectLastValue(underTest.educationTriggered) - assertThat(model).isNull() - } - - @Test - fun noEducationInfoWhenShortcutTriggeredPreviously() = - testScope.runTest { - val model by collectLastValue(underTest.educationTriggered) - contextualEduInteractor.updateShortcutTriggerTime(gestureType) - triggerMaxEducationSignals(gestureType) - assertThat(model).isNull() - } - - @Test - fun no2ndEducationBeforeMinEduIntervalReached() = - testScope.runTest { - val models by collectValues(underTest.educationTriggered) - triggerMaxEducationSignals(gestureType) - runCurrent() - - // Offset a duration that is less than the required education interval - eduClock.offset(1.seconds) - triggerMaxEducationSignals(gestureType) - runCurrent() - - assertThat(models.filterNotNull().size).isEqualTo(1) - } - - @Test - fun noNewEducationInfoAfterMaxEducationCountReached() = - testScope.runTest { - val models by collectValues(underTest.educationTriggered) - // Trigger 2 educations - triggerMaxEducationSignals(gestureType) - runCurrent() - eduClock.offset(minDurationForNextEdu) - triggerMaxEducationSignals(gestureType) - runCurrent() - - // Try triggering 3rd education - eduClock.offset(minDurationForNextEdu) - triggerMaxEducationSignals(gestureType) - - assertThat(models.filterNotNull().size).isEqualTo(2) - } - - @Test - fun startNewUsageSessionWhen2ndSignalReceivedAfterSessionDeadline() = - testScope.runTest { - val model by - collectLastValue( - kosmos.contextualEducationRepository.readGestureEduModelFlow(gestureType) - ) - contextualEduInteractor.incrementSignalCount(gestureType) - eduClock.offset(KeyboardTouchpadEduInteractor.usageSessionDuration.plus(1.seconds)) - val secondSignalReceivedTime = eduClock.instant() - contextualEduInteractor.incrementSignalCount(gestureType) - - assertThat(model) - .isEqualTo( - GestureEduModel( - signalCount = 1, - usageSessionStartTime = secondSignalReceivedTime, - userId = 0, - gestureType = gestureType, - ) - ) - } - - @Test - fun newTouchpadConnectionTimeOnFirstTouchpadConnected() = - testScope.runTest { - setIsAnyTouchpadConnected(true) - val model = contextualEduInteractor.getEduDeviceConnectionTime() - assertThat(model.touchpadFirstConnectionTime).isEqualTo(eduClock.instant()) - } - - @Test - fun unchangedTouchpadConnectionTimeOnSecondConnection() = - testScope.runTest { - val firstConnectionTime = eduClock.instant() - setIsAnyTouchpadConnected(true) - setIsAnyTouchpadConnected(false) - - eduClock.offset(1.hours) - setIsAnyTouchpadConnected(true) - - val model = contextualEduInteractor.getEduDeviceConnectionTime() - assertThat(model.touchpadFirstConnectionTime).isEqualTo(firstConnectionTime) - } - - @Test - fun newTouchpadConnectionTimeOnUserChanged() = - testScope.runTest { - // Touchpad connected for user 0 - setIsAnyTouchpadConnected(true) - - // Change user - eduClock.offset(1.hours) - val newUserFirstConnectionTime = eduClock.instant() - userRepository.setSelectedUserInfo(USER_INFOS[0]) - runCurrent() - - val model = contextualEduInteractor.getEduDeviceConnectionTime() - assertThat(model.touchpadFirstConnectionTime).isEqualTo(newUserFirstConnectionTime) - } - - @Test - fun newKeyboardConnectionTimeOnKeyboardConnected() = - testScope.runTest { - setIsAnyKeyboardConnected(true) - val model = contextualEduInteractor.getEduDeviceConnectionTime() - assertThat(model.keyboardFirstConnectionTime).isEqualTo(eduClock.instant()) - } - - @Test - fun unchangedKeyboardConnectionTimeOnSecondConnection() = - testScope.runTest { - val firstConnectionTime = eduClock.instant() - setIsAnyKeyboardConnected(true) - setIsAnyKeyboardConnected(false) - - eduClock.offset(1.hours) - setIsAnyKeyboardConnected(true) - - val model = contextualEduInteractor.getEduDeviceConnectionTime() - assertThat(model.keyboardFirstConnectionTime).isEqualTo(firstConnectionTime) - } - - @Test - fun newKeyboardConnectionTimeOnUserChanged() = - testScope.runTest { - // Keyboard connected for user 0 - setIsAnyKeyboardConnected(true) - - // Change user - eduClock.offset(1.hours) - val newUserFirstConnectionTime = eduClock.instant() - userRepository.setSelectedUserInfo(USER_INFOS[0]) - runCurrent() - - val model = contextualEduInteractor.getEduDeviceConnectionTime() - assertThat(model.keyboardFirstConnectionTime).isEqualTo(newUserFirstConnectionTime) - } - - @Test - fun updateShortcutTimeOnKeyboardShortcutTriggered() = - testScope.runTest { - // Only All Apps needs to update the keyboard shortcut - assumeTrue(gestureType == ALL_APPS) - kosmos.contextualEducationRepository.setKeyboardShortcutTriggered(ALL_APPS) - - val model by - collectLastValue( - kosmos.contextualEducationRepository.readGestureEduModelFlow(ALL_APPS) - ) - assertThat(model?.lastShortcutTriggeredTime).isEqualTo(eduClock.instant()) - } - - @Test - fun dataUpdatedOnIncrementSignalCountWhenTouchpadConnected() = - testScope.runTest { - assumeTrue(gestureType != ALL_APPS) - setUpForInitialDelayElapse() - touchpadRepository.setIsAnyTouchpadConnected(true) - - val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) - val originalValue = model!!.signalCount - val listener = getOverviewProxyListener() - listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) - - assertThat(model?.signalCount).isEqualTo(originalValue + 1) - } - - @Test - fun dataUnchangedOnIncrementSignalCountWhenTouchpadDisconnected() = - testScope.runTest { - setUpForInitialDelayElapse() - touchpadRepository.setIsAnyTouchpadConnected(false) - - val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) - val originalValue = model!!.signalCount - val listener = getOverviewProxyListener() - listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) - - assertThat(model?.signalCount).isEqualTo(originalValue) - } - - @Test - fun dataUpdatedOnIncrementSignalCountWhenKeyboardConnected() = - testScope.runTest { - assumeTrue(gestureType == ALL_APPS) - setUpForInitialDelayElapse() - keyboardRepository.setIsAnyKeyboardConnected(true) - - val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) - val originalValue = model!!.signalCount - val listener = getOverviewProxyListener() - listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) - - assertThat(model?.signalCount).isEqualTo(originalValue + 1) - } - - @Test - fun dataUnchangedOnIncrementSignalCountWhenKeyboardDisconnected() = + fun newEducationToastBeforeMaxToastsPerSessionTriggered() = testScope.runTest { + setUpForDeviceConnection() setUpForInitialDelayElapse() - keyboardRepository.setIsAnyKeyboardConnected(false) - - val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) - val originalValue = model!!.signalCount - val listener = getOverviewProxyListener() - listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) - - assertThat(model?.signalCount).isEqualTo(originalValue) - } - - @Test - fun dataAddedOnUpdateShortcutTriggerTime() = - testScope.runTest { - val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) - assertThat(model?.lastShortcutTriggeredTime).isNull() + val model by collectLastValue(underTest.educationTriggered) - val listener = getOverviewProxyListener() - listener.updateContextualEduStats(/* isTrackpadGesture= */ true, gestureType) + triggerEducation(HOME) - assertThat(model?.lastShortcutTriggeredTime).isEqualTo(kosmos.fakeEduClock.instant()) + assertThat(model).isEqualTo(EducationInfo(HOME, EducationUiType.Toast, userId = 0)) } @Test - fun dataUpdatedOnIncrementSignalCountAfterInitialDelay() = + fun noEducationToastAfterMaxToastsPerSessionTriggered() = testScope.runTest { setUpForDeviceConnection() - tutorialSchedulerRepository.updateLaunchTime(DeviceType.TOUCHPAD, eduClock.instant()) + setUpForInitialDelayElapse() + val models by collectValues(underTest.educationTriggered.filterNotNull()) + // Show two toasts of other gestures + triggerEducation(HOME) + triggerEducation(BACK) - val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) - val originalValue = model!!.signalCount - eduClock.offset(initialDelayElapsedDuration) - val listener = getOverviewProxyListener() - listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + triggerEducation(OVERVIEW) - assertThat(model?.signalCount).isEqualTo(originalValue + 1) + // No new toast education besides the 2 triggered at first + val firstEdu = EducationInfo(HOME, EducationUiType.Toast, userId = 0) + val secondEdu = EducationInfo(BACK, EducationUiType.Toast, userId = 0) + assertThat(models).containsExactly(firstEdu, secondEdu).inOrder() } @Test - fun dataUnchangedOnIncrementSignalCountBeforeInitialDelay() = + fun newEducationToastAfterMinIntervalElapsedWhenMaxToastsPerSessionTriggered() = testScope.runTest { setUpForDeviceConnection() - tutorialSchedulerRepository.updateLaunchTime(DeviceType.TOUCHPAD, eduClock.instant()) + setUpForInitialDelayElapse() + val models by collectValues(underTest.educationTriggered.filterNotNull()) + // Show two toasts of other gestures + triggerEducation(HOME) + triggerEducation(BACK) - val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) - val originalValue = model!!.signalCount - // No offset to the clock to simulate update before initial delay - val listener = getOverviewProxyListener() - listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + // Trigger toast after an usage session has elapsed + eduClock.offset(KeyboardTouchpadEduInteractor.usageSessionDuration + 1.seconds) + triggerEducation(OVERVIEW) - assertThat(model?.signalCount).isEqualTo(originalValue) + val firstEdu = EducationInfo(HOME, EducationUiType.Toast, userId = 0) + val secondEdu = EducationInfo(BACK, EducationUiType.Toast, userId = 0) + val thirdEdu = EducationInfo(OVERVIEW, EducationUiType.Toast, userId = 0) + assertThat(models).containsExactly(firstEdu, secondEdu, thirdEdu).inOrder() } @Test - fun dataUnchangedOnIncrementSignalCountWithoutOobeLaunchTime() = + fun newEducationNotificationAfterMaxToastsPerSessionTriggered() = testScope.runTest { - // No update to OOBE launch time to simulate no OOBE is launched yet setUpForDeviceConnection() + setUpForInitialDelayElapse() + val models by collectValues(underTest.educationTriggered.filterNotNull()) + triggerEducation(BACK) - val model by collectLastValue(repository.readGestureEduModelFlow(gestureType)) - val originalValue = model!!.signalCount - val listener = getOverviewProxyListener() - listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) + // Offset to let min interval for notification elapse so we could show edu notification + // for BACK. It would be a new usage session too because the interval (7 days) is + // longer than a usage session (3 days) + eduClock.offset(minIntervalForEduNotification) + triggerEducation(HOME) + triggerEducation(OVERVIEW) + triggerEducation(BACK) - assertThat(model?.signalCount).isEqualTo(originalValue) + val firstEdu = EducationInfo(BACK, EducationUiType.Toast, userId = 0) + val secondEdu = EducationInfo(HOME, EducationUiType.Toast, userId = 0) + val thirdEdu = EducationInfo(OVERVIEW, EducationUiType.Toast, userId = 0) + val fourthEdu = EducationInfo(BACK, EducationUiType.Notification, userId = 0) + assertThat(models).containsExactly(firstEdu, secondEdu, thirdEdu, fourthEdu).inOrder() } private suspend fun setUpForInitialDelayElapse() { @@ -402,51 +156,6 @@ class KeyboardTouchpadEduInteractorTest(private val gestureType: GestureType) : eduClock.offset(initialDelayElapsedDuration) } - fun logMetricsForToastEducation() = - testScope.runTest { - triggerMaxEducationSignals(gestureType) - runCurrent() - - verify(kosmos.mockEduMetricsLogger) - .logContextualEducationTriggered(gestureType, EducationUiType.Toast) - } - - @Test - fun logMetricsForNotificationEducation() = - testScope.runTest { - triggerMaxEducationSignals(gestureType) - runCurrent() - - eduClock.offset(minDurationForNextEdu) - triggerMaxEducationSignals(gestureType) - runCurrent() - - verify(kosmos.mockEduMetricsLogger) - .logContextualEducationTriggered(gestureType, EducationUiType.Notification) - } - - @After - fun clear() { - testScope.launch { tutorialSchedulerRepository.clear() } - } - - private suspend fun triggerMaxEducationSignals(gestureType: GestureType) { - // Increment max number of signal to try triggering education - for (i in 1..KeyboardTouchpadEduInteractor.MAX_SIGNAL_COUNT) { - contextualEduInteractor.incrementSignalCount(gestureType) - } - } - - private fun TestScope.setIsAnyTouchpadConnected(isConnected: Boolean) { - touchpadRepository.setIsAnyTouchpadConnected(isConnected) - runCurrent() - } - - private fun TestScope.setIsAnyKeyboardConnected(isConnected: Boolean) { - keyboardRepository.setIsAnyKeyboardConnected(isConnected) - runCurrent() - } - private fun setUpForDeviceConnection() { touchpadRepository.setIsAnyTouchpadConnected(true) keyboardRepository.setIsAnyKeyboardConnected(true) @@ -458,13 +167,12 @@ class KeyboardTouchpadEduInteractorTest(private val gestureType: GestureType) : return listenerCaptor.firstValue } - companion object { - private val USER_INFOS = listOf(UserInfo(101, "Second User", 0)) - - @JvmStatic - @Parameters(name = "{0}") - fun getGestureTypes(): List<GestureType> { - return listOf(BACK, HOME, OVERVIEW, ALL_APPS) + private fun TestScope.triggerEducation(gestureType: GestureType) { + // Increment max number of signal to try triggering education + for (i in 1..KeyboardTouchpadEduInteractor.MAX_SIGNAL_COUNT) { + val listener = getOverviewProxyListener() + listener.updateContextualEduStats(/* isTrackpadGesture= */ false, gestureType) } + runCurrent() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt index d88d69da5e59..d2317e4f533d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/DragAndDropTest.kt @@ -22,7 +22,10 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.SemanticsProperties +import androidx.compose.ui.test.SemanticsMatcher import androidx.compose.ui.test.assert +import androidx.compose.ui.test.filter import androidx.compose.ui.test.hasContentDescription import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.createComposeRule @@ -182,11 +185,14 @@ class DragAndDropTest : SysuiTestCase() { } private fun ComposeContentTestRule.assertTileGridContainsExactly(specs: List<String>) { - onNodeWithTag(CURRENT_TILES_GRID_TEST_TAG).onChildren().apply { - fetchSemanticsNodes().forEachIndexed { index, _ -> - get(index).assert(hasContentDescription(specs[index])) + onNodeWithTag(CURRENT_TILES_GRID_TEST_TAG) + .onChildren() + .filter(SemanticsMatcher.keyIsDefined(SemanticsProperties.ContentDescription)) + .apply { + fetchSemanticsNodes().forEachIndexed { index, _ -> + get(index).assert(hasContentDescription(specs[index])) + } } - } } companion object { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt index 9a924ed5a630..d8d6f2e9fbb0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt @@ -4,9 +4,10 @@ import android.bluetooth.BluetoothDevice import android.os.Handler import android.os.Looper import android.os.UserManager +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger import com.android.internal.telephony.flags.Flags @@ -22,8 +23,11 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment +import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIconWithRes import com.android.systemui.res.R import com.android.systemui.statusbar.policy.BluetoothController import com.android.systemui.util.mockito.any @@ -41,11 +45,17 @@ import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @RunWithLooper(setAsMainLooper = true) @SmallTest -class BluetoothTileTest : SysuiTestCase() { +class BluetoothTileTest(flags: FlagsParameterization) : SysuiTestCase() { + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } @Mock private lateinit var qsLogger: QSLogger @Mock private lateinit var qsHost: QSHost @@ -81,7 +91,7 @@ class BluetoothTileTest : SysuiTestCase() { qsLogger, bluetoothController, featureFlags, - bluetoothTileDialogViewModel + bluetoothTileDialogViewModel, ) tile.initialize() @@ -109,8 +119,7 @@ class BluetoothTileTest : SysuiTestCase() { tile.handleUpdateState(state, /* arg= */ null) - assertThat(state.icon) - .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_off)) + assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_bluetooth_icon_off)) } @Test @@ -121,8 +130,7 @@ class BluetoothTileTest : SysuiTestCase() { tile.handleUpdateState(state, /* arg= */ null) - assertThat(state.icon) - .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_off)) + assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_bluetooth_icon_off)) } @Test @@ -133,8 +141,7 @@ class BluetoothTileTest : SysuiTestCase() { tile.handleUpdateState(state, /* arg= */ null) - assertThat(state.icon) - .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_on)) + assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_bluetooth_icon_on)) } @Test @@ -145,8 +152,7 @@ class BluetoothTileTest : SysuiTestCase() { tile.handleUpdateState(state, /* arg= */ null) - assertThat(state.icon) - .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_bluetooth_icon_search)) + assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_bluetooth_icon_search)) } @Test @@ -161,11 +167,10 @@ class BluetoothTileTest : SysuiTestCase() { .isEqualTo( mContext.getString( R.string.quick_settings_bluetooth_secondary_label_battery_level, - Utils.formatPercentage(50) + Utils.formatPercentage(50), ) ) - verify(bluetoothController) - .addOnMetadataChangedListener(eq(cachedDevice), any(), any()) + verify(bluetoothController).addOnMetadataChangedListener(eq(cachedDevice), any(), any()) } @Test @@ -186,7 +191,7 @@ class BluetoothTileTest : SysuiTestCase() { .isEqualTo( mContext.getString( R.string.quick_settings_bluetooth_secondary_label_battery_level, - Utils.formatPercentage(25) + Utils.formatPercentage(25), ) ) verify(bluetoothController, times(1)) @@ -197,7 +202,7 @@ class BluetoothTileTest : SysuiTestCase() { fun handleClick_hasSatelliteFeatureButNoQsTileDialogAndClickIsProcessing_doNothing() { mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG)) - .thenReturn(false) + .thenReturn(false) `when`(clickJob.isCompleted).thenReturn(false) tile.mClickJob = clickJob @@ -210,7 +215,7 @@ class BluetoothTileTest : SysuiTestCase() { fun handleClick_noSatelliteFeatureAndNoQsTileDialog_directSetBtEnable() { mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG)) - .thenReturn(false) + .thenReturn(false) tile.handleClick(null) @@ -221,7 +226,7 @@ class BluetoothTileTest : SysuiTestCase() { fun handleClick_noSatelliteFeatureButHasQsTileDialog_showDialog() { mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG)) - .thenReturn(true) + .thenReturn(true) tile.handleClick(null) @@ -265,7 +270,7 @@ class BluetoothTileTest : SysuiTestCase() { qsLogger: QSLogger, bluetoothController: BluetoothController, featureFlags: FeatureFlagsClassic, - bluetoothTileDialogViewModel: BluetoothTileDialogViewModel + bluetoothTileDialogViewModel: BluetoothTileDialogViewModel, ) : BluetoothTile( qsHost, @@ -279,13 +284,13 @@ class BluetoothTileTest : SysuiTestCase() { qsLogger, bluetoothController, featureFlags, - bluetoothTileDialogViewModel + bluetoothTileDialogViewModel, ) { var restrictionChecked: String? = null override fun checkIfRestrictionEnforcedByAdminOnly( state: QSTile.State?, - userRestriction: String? + userRestriction: String?, ) { restrictionChecked = userRestriction } @@ -321,7 +326,7 @@ class BluetoothTileTest : SysuiTestCase() { fun listenToDeviceMetadata( state: QSTile.BooleanState, cachedDevice: CachedBluetoothDevice, - batteryLevel: Int + batteryLevel: Int, ) { val btDevice = mock<BluetoothDevice>() whenever(cachedDevice.device).thenReturn(btDevice) @@ -332,4 +337,20 @@ class BluetoothTileTest : SysuiTestCase() { addConnectedDevice(cachedDevice) tile.handleUpdateState(state, /* arg= */ null) } + + private fun createExpectedIcon(resId: Int): QSTile.Icon { + return if (isEnabled) { + DrawableIconWithRes(mContext.getDrawable(resId), resId) + } else { + QSTileImpl.ResourceIcon.get(resId) + } + } + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt index 6a43a61dad77..55fb6dacfc3a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt @@ -21,15 +21,15 @@ import android.content.ContextWrapper import android.content.SharedPreferences import android.os.Handler import android.platform.test.annotations.DisableFlags +import android.platform.test.flag.junit.FlagsParameterization +import android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf import android.provider.Settings import android.provider.Settings.Global.ZEN_MODE_NO_INTERRUPTIONS import android.provider.Settings.Global.ZEN_MODE_OFF import android.testing.TestableLooper import android.view.ContextThemeWrapper -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable @@ -39,14 +39,19 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger +import com.android.systemui.qs.flags.QSComposeFragment +import com.android.systemui.qs.flags.QsInCompose.isEnabled import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIconWithRes +import com.android.systemui.res.R import com.android.systemui.statusbar.policy.ZenModeController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.nullable import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.SecureSettings import com.google.common.truth.Truth.assertThat +import java.io.File import org.junit.After import org.junit.Before import org.junit.Test @@ -55,56 +60,55 @@ import org.mockito.Mock import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.never import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations -import java.io.File import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @SmallTest -@RunWith(AndroidJUnit4::class) +@RunWith(ParameterizedAndroidJunit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @DisableFlags(android.app.Flags.FLAG_MODES_UI) -class DndTileTest : SysuiTestCase() { +class DndTileTest(flags: FlagsParameterization) : SysuiTestCase() { companion object { private const val DEFAULT_USER = 0 private const val KEY = Settings.Secure.ZEN_DURATION + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return allCombinationsOf(QSComposeFragment.FLAG_NAME) + } + } + + init { + mSetFlagsRule.setFlagsParameterization(flags) } - @Mock - private lateinit var qsHost: QSHost + @Mock private lateinit var qsHost: QSHost - @Mock - private lateinit var metricsLogger: MetricsLogger + @Mock private lateinit var metricsLogger: MetricsLogger - @Mock - private lateinit var statusBarStateController: StatusBarStateController + @Mock private lateinit var statusBarStateController: StatusBarStateController - @Mock - private lateinit var activityStarter: ActivityStarter + @Mock private lateinit var activityStarter: ActivityStarter - @Mock - private lateinit var qsLogger: QSLogger + @Mock private lateinit var qsLogger: QSLogger - @Mock - private lateinit var uiEventLogger: QsEventLogger + @Mock private lateinit var uiEventLogger: QsEventLogger - @Mock - private lateinit var zenModeController: ZenModeController + @Mock private lateinit var zenModeController: ZenModeController - @Mock - private lateinit var sharedPreferences: SharedPreferences + @Mock private lateinit var sharedPreferences: SharedPreferences - @Mock - private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator + @Mock private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator - @Mock - private lateinit var hostDialog: Dialog + @Mock private lateinit var hostDialog: Dialog - @Mock - private lateinit var expandable: Expandable + @Mock private lateinit var expandable: Expandable - @Mock - private lateinit var controller: DialogTransitionAnimator.Controller + @Mock private lateinit var controller: DialogTransitionAnimator.Controller private lateinit var secureSettings: SecureSettings private lateinit var testableLooper: TestableLooper @@ -118,31 +122,32 @@ class DndTileTest : SysuiTestCase() { whenever(qsHost.userId).thenReturn(DEFAULT_USER) - val wrappedContext = object : ContextWrapper( - ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings) - ) { - override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { - return sharedPreferences + val wrappedContext = + object : + ContextWrapper(ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)) { + override fun getSharedPreferences(file: File?, mode: Int): SharedPreferences { + return sharedPreferences + } } - } whenever(qsHost.context).thenReturn(wrappedContext) whenever(expandable.dialogTransitionController(any())).thenReturn(controller) - tile = DndTile( - qsHost, - uiEventLogger, - testableLooper.looper, - Handler(testableLooper.looper), - FalsingManagerFake(), - metricsLogger, - statusBarStateController, - activityStarter, - qsLogger, - zenModeController, - sharedPreferences, - secureSettings, - mDialogTransitionAnimator - ) + tile = + DndTile( + qsHost, + uiEventLogger, + testableLooper.looper, + Handler(testableLooper.looper), + FalsingManagerFake(), + metricsLogger, + statusBarStateController, + activityStarter, + qsLogger, + zenModeController, + sharedPreferences, + secureSettings, + mDialogTransitionAnimator, + ) } @After @@ -222,7 +227,7 @@ class DndTileTest : SysuiTestCase() { tile.handleUpdateState(state, /* arg= */ null) - assertThat(state.icon).isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_dnd_icon_off)) + assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_dnd_icon_off)) } @Test @@ -232,6 +237,14 @@ class DndTileTest : SysuiTestCase() { tile.handleUpdateState(state, /* arg= */ null) - assertThat(state.icon).isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_dnd_icon_on)) + assertThat(state.icon).isEqualTo(createExpectedIcon(R.drawable.qs_dnd_icon_on)) + } + + private fun createExpectedIcon(resId: Int): QSTile.Icon { + return if (isEnabled) { + DrawableIconWithRes(mContext.getDrawable(resId), resId) + } else { + QSTileImpl.ResourceIcon.get(resId) + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java index 190d80f9f6c4..5f63b15916a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DreamTileTest.java @@ -16,6 +16,10 @@ package com.android.systemui.qs.tiles; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; + import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertTrue; @@ -32,12 +36,12 @@ import android.content.Intent; import android.content.pm.UserInfo; import android.os.Handler; import android.os.RemoteException; +import android.platform.test.flag.junit.FlagsParameterization; import android.provider.Settings; import android.service.dreams.IDreamManager; import android.service.quicksettings.Tile; import android.testing.TestableLooper; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; @@ -45,9 +49,11 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; +import com.android.systemui.qs.flags.QsInCompose; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; @@ -63,11 +69,21 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -@RunWith(AndroidJUnit4.class) +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + +@RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class DreamTileTest extends SysuiTestCase { + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + @Mock private ActivityStarter mActivityStarter; @Mock @@ -101,6 +117,11 @@ public class DreamTileTest extends SysuiTestCase { private final String mExpectedTileLabel = mContext.getResources().getString( R.string.quick_settings_screensaver_label); + public DreamTileTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -246,13 +267,13 @@ public class DreamTileTest extends SysuiTestCase { dockIntent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_DESK); receiver.onReceive(mContext, dockIntent); mTestableLooper.processAllMessages(); - assertEquals(QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_screen_saver), + assertEquals(createExpectedIcon(R.drawable.ic_qs_screen_saver), dockedTile.getState().icon); dockIntent.putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED); receiver.onReceive(mContext, dockIntent); mTestableLooper.processAllMessages(); - assertEquals(QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_screen_saver_undocked), + assertEquals(createExpectedIcon(R.drawable.ic_qs_screen_saver_undocked), dockedTile.getState().icon); destroyTile(dockedTile); @@ -268,6 +289,14 @@ public class DreamTileTest extends SysuiTestCase { mTestableLooper.processAllMessages(); } + private QSTile.Icon createExpectedIcon(int resId) { + if (QsInCompose.isEnabled()) { + return new QSTileImpl.DrawableIconWithRes(mContext.getDrawable(resId), resId); + } else { + return QSTileImpl.ResourceIcon.get(resId); + } + } + private DreamTile constructTileForTest(boolean dreamSupported, boolean dreamOnlyEnabledForSystemUser) { return new DreamTile( diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java index 5bd6944e863f..ba6c2dc4f705 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/HotspotTileTest.java @@ -16,16 +16,20 @@ package com.android.systemui.qs.tiles; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.os.Handler; +import android.platform.test.flag.junit.FlagsParameterization; import android.service.quicksettings.Tile; import android.testing.TestableLooper; -import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.dx.mockito.inline.extended.ExtendedMockito; @@ -38,6 +42,7 @@ import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; +import com.android.systemui.qs.flags.QsInCompose; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; @@ -54,11 +59,21 @@ import org.mockito.MockitoSession; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -@RunWith(AndroidJUnit4.class) +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + +@RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class HotspotTileTest extends SysuiTestCase { + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + @Rule public MockitoRule mRule = MockitoJUnit.rule(); @Mock @@ -74,6 +89,11 @@ public class HotspotTileTest extends SysuiTestCase { private HotspotTile mTile; private QSTile.BooleanState mState = new QSTile.BooleanState(); + public HotspotTileTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { mTestableLooper = TestableLooper.get(this); @@ -144,7 +164,7 @@ public class HotspotTileTest extends SysuiTestCase { mTile.handleUpdateState(state, /* arg= */ null); assertThat(state.icon) - .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_hotspot_icon_off)); + .isEqualTo(createExpectedIcon(R.drawable.qs_hotspot_icon_off)); } @Test @@ -156,7 +176,7 @@ public class HotspotTileTest extends SysuiTestCase { mTile.handleUpdateState(state, /* arg= */ null); assertThat(state.icon) - .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_hotspot_icon_search)); + .isEqualTo(createExpectedIcon(R.drawable.qs_hotspot_icon_search)); } @Test @@ -168,6 +188,14 @@ public class HotspotTileTest extends SysuiTestCase { mTile.handleUpdateState(state, /* arg= */ null); assertThat(state.icon) - .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_hotspot_icon_on)); + .isEqualTo(createExpectedIcon(R.drawable.qs_hotspot_icon_on)); + } + + private QSTile.Icon createExpectedIcon(int resId) { + if (QsInCompose.isEnabled()) { + return new QSTileImpl.DrawableIconWithRes(mContext.getDrawable(resId), resId); + } else { + return QSTileImpl.ResourceIcon.get(resId); + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java index 5ada2f3fd63d..b26f0a6e71a3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java @@ -260,7 +260,8 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { @Test public void connectCarrierNetwork_mergedCarrierEntryCanConnect_connectAndCreateSysUiToast() { - when(mTelephonyManager.isDataEnabled()).thenReturn(true); + InternetDialogController spyController = spy(mInternetDialogController); + when(spyController.isMobileDataEnabled()).thenReturn(true); when(mKeyguardStateController.isUnlocked()).thenReturn(true); when(mConnectivityManager.getActiveNetwork()).thenReturn(mNetwork); when(mConnectivityManager.getNetworkCapabilities(mNetwork)) @@ -272,7 +273,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now, TOAST_MESSAGE_STRING); - mInternetDialogController.connectCarrierNetwork(); + spyController.connectCarrierNetwork(); verify(mMergedCarrierEntry).connect(null /* callback */, false /* showToast */); verify(mToastFactory).createToast(any(), any(), eq(TOAST_MESSAGE_STRING), anyString(), @@ -281,11 +282,12 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { @Test public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenSettingsOff() { - when(mTelephonyManager.isDataEnabled()).thenReturn(false); - + InternetDialogController spyController = spy(mInternetDialogController); + when(spyController.isMobileDataEnabled()).thenReturn(false); mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now, TOAST_MESSAGE_STRING); - mInternetDialogController.connectCarrierNetwork(); + + spyController.connectCarrierNetwork(); verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */); verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(), @@ -294,12 +296,13 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { @Test public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenKeyguardLocked() { - when(mTelephonyManager.isDataEnabled()).thenReturn(true); + InternetDialogController spyController = spy(mInternetDialogController); + when(spyController.isMobileDataEnabled()).thenReturn(true); when(mKeyguardStateController.isUnlocked()).thenReturn(false); mTestableResources.addOverride(R.string.wifi_wont_autoconnect_for_now, TOAST_MESSAGE_STRING); - mInternetDialogController.connectCarrierNetwork(); + spyController.connectCarrierNetwork(); verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */); verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(), @@ -308,7 +311,8 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { @Test public void connectCarrierNetwork_mergedCarrierEntryCanConnect_doNothingWhenMobileIsPrimary() { - when(mTelephonyManager.isDataEnabled()).thenReturn(true); + InternetDialogController spyController = spy(mInternetDialogController); + when(spyController.isMobileDataEnabled()).thenReturn(true); when(mKeyguardStateController.isUnlocked()).thenReturn(true); when(mConnectivityManager.getActiveNetwork()).thenReturn(mNetwork); when(mConnectivityManager.getNetworkCapabilities(mNetwork)) @@ -446,10 +450,9 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { when(mWifiStateWorker.isWifiEnabled()).thenReturn(true); spyController.onAccessPointsChanged(null /* accessPoints */); - doReturn(SUB_ID2).when(spyController).getActiveAutoSwitchNonDdsSubId(); + doReturn(SUB_ID).when(spyController).getActiveAutoSwitchNonDdsSubId(); doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState(); - doReturn(mServiceState).when(mTelephonyManager).getServiceState(); - doReturn(TelephonyManager.DATA_DISCONNECTED).when(mTelephonyManager).getDataState(); + spyController.mSubIdServiceState.put(SUB_ID2, mServiceState); assertFalse(TextUtils.equals(spyController.getSubtitleText(false), getResourcesString("all_network_unavailable"))); @@ -469,8 +472,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { spyController.onAccessPointsChanged(null /* accessPoints */); doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState(); - doReturn(mServiceState).when(mTelephonyManager).getServiceState(); - doReturn(TelephonyManager.DATA_DISCONNECTED).when(mTelephonyManager).getDataState(); + spyController.mSubIdServiceState.put(SUB_ID, mServiceState); assertTrue(TextUtils.equals(spyController.getSubtitleText(false), getResourcesString("all_network_unavailable"))); @@ -487,11 +489,10 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { fakeAirplaneModeEnabled(false); when(mWifiStateWorker.isWifiEnabled()).thenReturn(true); mInternetDialogController.onAccessPointsChanged(null /* accessPoints */); + InternetDialogController spyController = spy(mInternetDialogController); doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState(); - doReturn(mServiceState).when(mTelephonyManager).getServiceState(); - - when(mTelephonyManager.isDataEnabled()).thenReturn(false); + spyController.mSubIdServiceState.put(SUB_ID, mServiceState); assertThat(mInternetDialogController.getSubtitleText(false)) .isEqualTo(getResourcesString("non_carrier_network_unavailable")); @@ -499,6 +500,9 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { // if the Wi-Fi disallow config, then don't return Wi-Fi related string. mInternetDialogController.mCanConfigWifi = false; + when(spyController.isMobileDataEnabled()).thenReturn(false); + + assertThat(mInternetDialogController.getSubtitleText(false)) .isNotEqualTo(getResourcesString("non_carrier_network_unavailable")); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index 6912eda3c3d4..d157cf2d51e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -36,8 +36,6 @@ import static com.android.systemui.statusbar.phone.CentralSurfaces.MSG_DISMISS_K import static com.google.common.truth.Truth.assertThat; -import static kotlinx.coroutines.flow.FlowKt.flowOf; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -56,6 +54,8 @@ import static org.mockito.Mockito.when; import static java.util.Collections.emptySet; +import static kotlinx.coroutines.flow.FlowKt.flowOf; + import android.app.ActivityManager; import android.app.IWallpaperManager; import android.app.NotificationManager; @@ -138,6 +138,7 @@ import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.plugins.PluginManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.domain.interactor.PowerInteractor; +import com.android.systemui.qs.flags.QSComposeFragment; import com.android.systemui.res.R; import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor; import com.android.systemui.scene.domain.startable.ScrimStartable; @@ -181,6 +182,7 @@ import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.AvalancheProvider; import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider; @@ -198,7 +200,6 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.ExtensionController; -import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.UserInfoControllerImpl; import com.android.systemui.statusbar.window.StatusBarWindowController; @@ -217,10 +218,6 @@ import com.android.systemui.volume.VolumeComponent; import com.android.wm.shell.bubbles.Bubbles; import com.android.wm.shell.startingsurface.StartingSurface; -import dagger.Lazy; - -import kotlinx.coroutines.test.TestScope; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -237,6 +234,9 @@ import java.util.Set; import javax.inject.Provider; +import dagger.Lazy; +import kotlinx.coroutines.test.TestScope; + @SmallTest @RunWith(AndroidJUnit4.class) @RunWithLooper(setAsMainLooper = true) @@ -667,6 +667,9 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mCentralSurfaces.startKeyguard(); mInitController.executePostInitTasks(); mCentralSurfaces.registerCallbacks(); + // Clear first invocations caused by registering flows with JavaAdapter + mTestScope.getTestScheduler().runCurrent(); + clearInvocations(mScrimController); } @Test @@ -1159,8 +1162,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test @EnableSceneContainer - public void brightnesShowingChanged_flagEnabled_ScrimControllerNotified() { - mCentralSurfaces.registerCallbacks(); + public void brightnesShowingChanged_sceneContainerFlagEnabled_ScrimControllerNotified() { final ScrimStartable scrimStartable = mKosmos.getScrimStartable(); scrimStartable.start(); @@ -1178,9 +1180,25 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Test @DisableSceneContainer - public void brightnesShowingChanged_flagDisabled_ScrimControllerNotified() { - mCentralSurfaces.registerCallbacks(); + @EnableFlags(QSComposeFragment.FLAG_NAME) + public void brightnesShowingChanged_qsUiRefactorFlagEnabled_ScrimControllerNotified() { + mBrightnessMirrorShowingInteractor.setMirrorShowing(true); + mTestScope.getTestScheduler().runCurrent(); + verify(mScrimController, atLeastOnce()).legacyTransitionTo(ScrimState.BRIGHTNESS_MIRROR); + clearInvocations(mScrimController); + + mBrightnessMirrorShowingInteractor.setMirrorShowing(false); + mTestScope.getTestScheduler().runCurrent(); + ArgumentCaptor<ScrimState> captor = ArgumentCaptor.forClass(ScrimState.class); + // The default is to call the one with the callback argument + verify(mScrimController, atLeastOnce()).legacyTransitionTo(captor.capture(), any()); + assertThat(captor.getValue()).isNotEqualTo(ScrimState.BRIGHTNESS_MIRROR); + } + @Test + @DisableSceneContainer + @DisableFlags(QSComposeFragment.FLAG_NAME) + public void brightnesShowingChanged_flagsDisabled_ScrimControllerNotified() { mBrightnessMirrorShowingInteractor.setMirrorShowing(true); mTestScope.getTestScheduler().runCurrent(); verify(mScrimController, never()).legacyTransitionTo(ScrimState.BRIGHTNESS_MIRROR); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt new file mode 100644 index 000000000000..b407b1ba227a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/ui/viewmodel/CommunalToDreamButtonViewModelKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.viewmodel + +import android.service.dream.dreamManager +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.statusbar.policy.batteryController + +val Kosmos.communalToDreamButtonViewModel by + Kosmos.Fixture { + CommunalToDreamButtonViewModel( + backgroundContext = testDispatcher, + batteryController = batteryController, + dreamManager = dreamManager, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryKosmos.kt index 1df3ef48d5a7..1021169c4b3b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/education/data/repository/ContextualEducationRepositoryKosmos.kt @@ -17,9 +17,11 @@ package com.android.systemui.education.data.repository import com.android.systemui.kosmos.Kosmos +import java.time.Duration import java.time.Instant var Kosmos.contextualEducationRepository: FakeContextualEducationRepository by Kosmos.Fixture { FakeContextualEducationRepository() } -var Kosmos.fakeEduClock: FakeEduClock by Kosmos.Fixture { FakeEduClock(Instant.MIN) } +var Kosmos.fakeEduClock: FakeEduClock by + Kosmos.Fixture { FakeEduClock(Instant.ofEpochSecond(Duration.ofDays(30).seconds)) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/FakeQSTileUserActionInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/FakeQSTileUserActionInteractor.kt index 597d52dcb299..bc1c60c33d71 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/FakeQSTileUserActionInteractor.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/interactor/FakeQSTileUserActionInteractor.kt @@ -16,6 +16,8 @@ package com.android.systemui.qs.tiles.base.interactor +import com.android.systemui.plugins.qs.TileDetailsViewModel +import com.android.systemui.qs.FakeTileDetailsViewModel import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -31,4 +33,7 @@ class FakeQSTileUserActionInteractor<T> : QSTileUserActionInteractor<T> { override suspend fun handleInput(input: QSTileInput<T>) { mutex.withLock { mutableInputs.add(input) } } + + override var detailsViewModel: TileDetailsViewModel? = + FakeTileDetailsViewModel("FakeQSTileUserActionInteractor") } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt index 4a249a8591e9..88bf9a5f2d5b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorKosmos.kt @@ -42,6 +42,6 @@ var Kosmos.sensitiveContentCoordinator: SensitiveContentCoordinator by sensitiveNotificationProtectionController, deviceEntryInteractor, sceneInteractor, - testScope, + testScope.backgroundScope, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt index c8ba551c518a..34661ced71b2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/ringer/ui/viewmodel/VolumeDialogRingerDrawerViewModelKosmos.kt @@ -21,6 +21,7 @@ import com.android.systemui.haptics.vibratorHelper import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.statusbar.notification.domain.interactor.notificationsSoundPolicyInteractor import com.android.systemui.volume.dialog.domain.interactor.volumeDialogVisibilityInteractor import com.android.systemui.volume.dialog.ringer.domain.volumeDialogRingerInteractor import com.android.systemui.volume.dialog.shared.volumeDialogLogger @@ -31,7 +32,8 @@ val Kosmos.volumeDialogRingerDrawerViewModel by applicationContext = applicationContext, backgroundDispatcher = testDispatcher, coroutineScope = applicationCoroutineScope, - interactor = volumeDialogRingerInteractor, + soundPolicyInteractor = notificationsSoundPolicyInteractor, + ringerInteractor = volumeDialogRingerInteractor, vibrator = vibratorHelper, volumeDialogLogger = volumeDialogLogger, visibilityInteractor = volumeDialogVisibilityInteractor, diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig index 5e1b1473d233..9c83757f4b0f 100644 --- a/services/autofill/bugfixes.aconfig +++ b/services/autofill/bugfixes.aconfig @@ -9,6 +9,16 @@ flag { } flag { + name: "improve_fill_dialog_aconfig" + namespace: "autofill" + description: "Improvements for Fill Dialog. Guard DeviceConfig rollout " + bug: "382493181" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "fill_fields_from_current_session_only" namespace: "autofill" description: "Only fill autofill fields that are part of the current session." diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java index 219b788448e8..5e7e557d7041 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java +++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java @@ -354,6 +354,13 @@ final class AutofillInlineSuggestionsRequestSession { } } + private void handleOnInputMethodStartInputView() { + synchronized (mLock) { + mUiCallback.onInputMethodStartInputView(); + handleOnReceiveImeStatusUpdated(true, true); + } + } + /** * Handles the IME session status received from the IME. * @@ -437,8 +444,8 @@ final class AutofillInlineSuggestionsRequestSession { final AutofillInlineSuggestionsRequestSession session = mSession.get(); if (session != null) { session.mHandler.sendMessage(obtainMessage( - AutofillInlineSuggestionsRequestSession::handleOnReceiveImeStatusUpdated, - session, true, true)); + AutofillInlineSuggestionsRequestSession::handleOnInputMethodStartInputView, + session)); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 259ea148f163..cba8c66cd5e3 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -2139,6 +2139,32 @@ public final class AutofillManagerService } @Override + public void notifyImeAnimationStart(int sessionId, long startTimeMs, int userId) { + synchronized (mLock) { + final AutofillManagerServiceImpl service = + peekServiceForUserWithLocalBinderIdentityLocked(userId); + if (service != null) { + service.notifyImeAnimationStart(sessionId, startTimeMs, getCallingUid()); + } else if (sVerbose) { + Slog.v(TAG, "notifyImeAnimationStart(): no service for " + userId); + } + } + } + + @Override + public void notifyImeAnimationEnd(int sessionId, long endTimeMs, int userId) { + synchronized (mLock) { + final AutofillManagerServiceImpl service = + peekServiceForUserWithLocalBinderIdentityLocked(userId); + if (service != null) { + service.notifyImeAnimationEnd(sessionId, endTimeMs, getCallingUid()); + } else if (sVerbose) { + Slog.v(TAG, "notifyImeAnimationEnd(): no service for " + userId); + } + } + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 5cf96bfb2b8b..0fa43ac7091b 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -823,6 +823,36 @@ final class AutofillManagerServiceImpl } @GuardedBy("mLock") + public void notifyImeAnimationStart(int sessionId, long startTimeMs, int uid) { + if (!isEnabledLocked()) { + Slog.wtf(TAG, "Service not enabled"); + return; + } + final Session session = mSessions.get(sessionId); + if (session == null || uid != session.uid) { + Slog.v(TAG, "notifyImeAnimationStart(): no session for " + + sessionId + "(" + uid + ")"); + return; + } + session.notifyImeAnimationStart(startTimeMs); + } + + @GuardedBy("mLock") + public void notifyImeAnimationEnd(int sessionId, long endTimeMs, int uid) { + if (!isEnabledLocked()) { + Slog.wtf(TAG, "Service not enabled"); + return; + } + final Session session = mSessions.get(sessionId); + if (session == null || uid != session.uid) { + Slog.v(TAG, "notifyImeAnimationEnd(): no session for " + + sessionId + "(" + uid + ")"); + return; + } + session.notifyImeAnimationEnd(endTimeMs); + } + + @GuardedBy("mLock") @Override // from PerUserSystemService protected void handlePackageUpdateLocked(@NonNull String packageName) { final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo(); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 6b227d7a876e..9c6e4741730a 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -40,6 +40,7 @@ import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE; import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; import static android.service.autofill.Flags.highlightAutofillSingleField; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED; import static android.view.autofill.AutofillManager.ACTION_START_SESSION; import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED; @@ -50,6 +51,7 @@ import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN; import static android.view.autofill.AutofillManager.EXTRA_AUTOFILL_REQUEST_ID; import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM; import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; + import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_EXPLICITLY_REQUESTED; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_NORMAL_TRIGGER; @@ -184,6 +186,7 @@ import android.view.autofill.IAutoFillManagerClient; import android.view.autofill.IAutofillWindowPresenter; import android.view.inputmethod.InlineSuggestionsRequest; import android.widget.RemoteViews; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; @@ -195,6 +198,7 @@ import com.android.server.autofill.ui.InlineFillUi; import com.android.server.autofill.ui.PendingUi; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; + import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -248,6 +252,8 @@ final class Session private static final int DEFAULT__FILL_REQUEST_ID_SNAPSHOT = -2; private static final int DEFAULT__FIELD_CLASSIFICATION_REQUEST_ID_SNAPSHOT = -2; + private static final long DEFAULT_UNASSIGNED_TIME = -1; + static final String SESSION_ID_KEY = "autofill_session_id"; static final String REQUEST_ID_KEY = "autofill_request_id"; @@ -292,6 +298,31 @@ final class Session @Retention(RetentionPolicy.SOURCE) @interface SessionState {} + /** + * Indicates fill dialog will not be shown. + */ + private static final int SHOW_FILL_DIALOG_NO = 0; + + /** + * Indicates fill dialog is shown. + */ + private static final int SHOW_FILL_DIALOG_YES = 1; + + /** + * Indicates fill dialog can be shown, but we need to wait. + * For eg, if the IME animation is happening, we need for it to complete before fill dialog can + * be shown. + */ + private static final int SHOW_FILL_DIALOG_WAIT = 2; + + @IntDef(prefix = { "SHOW_FILL_DIALOG_" }, value = { + SHOW_FILL_DIALOG_NO, + SHOW_FILL_DIALOG_YES, + SHOW_FILL_DIALOG_WAIT + }) + @Retention(RetentionPolicy.SOURCE) + private @interface ShowFillDialogState{} + @GuardedBy("mLock") private final SessionFlags mSessionFlags; @@ -576,6 +607,47 @@ final class Session private boolean mIgnoreViewStateResetToEmpty; + /** + * Whether improveFillDialog feature is enabled or not. + * Configured via device config flag and aconfig flag. + */ + private final boolean mImproveFillDialogEnabled; + + /** + * Timeout, after which, fill dialog won't be shown. + * Configured via device config flag. + */ + private final long mFillDialogTimeoutMs; + + /** + * Time to wait after ime Animation ends before showing up fill dialog. + * Configured via device config flag. + */ + private final long mFillDialogMinWaitAfterImeAnimationMs; + + /** + * Indicates the need to wait for ime animation to end before showing up fill dialog. + * This is set when we receive notification of ime animation start. + * Focussing on one input field from another wouldn't cause ime to re-animate. So this will let + * us know whether we need to wait for ime animation finish notification. + */ + private boolean mWaitForImeAnimation; + + /** + * A runnable set to run when there is a need to wait for ime animation to end before showing + * up fill dialog. This is set only if the fill response has been received, and the response + * is eligible for showing up fill dialog, but the ime animation hasn't completed. This allows + * for this runnable to be scheduled/run when the ime animation ends, in order to show fill + * dialog. + */ + private Runnable mFillDialogRunnable; + + private long mImeAnimationFinishTimeMs = DEFAULT_UNASSIGNED_TIME; + + private long mImeAnimationStartTimeMs = DEFAULT_UNASSIGNED_TIME; + + private long mLastInputStartTime = DEFAULT_UNASSIGNED_TIME; + /* * Id of the previous view that was entered. Once set, it would only be replaced by non-null * view ids. @@ -1493,6 +1565,12 @@ final class Session // Now request the assist structure data. requestAssistStructureLocked(requestId, flags); + if (mImproveFillDialogEnabled) { + // New request has been sent, so re-enable fill dialog. + // Fill dialog is eligible to be shown after each Fill request. + enableFillDialog(); + } + return Optional.of(requestId); } @@ -1657,6 +1735,11 @@ final class Session mSaveEventLogger = SaveEventLogger.forSessionId(sessionId, mLatencyBaseTime); mIsPrimaryCredential = isPrimaryCredential; mIgnoreViewStateResetToEmpty = AutofillFeatureFlags.shouldIgnoreViewStateResetToEmpty(); + mImproveFillDialogEnabled = + improveFillDialogAconfig() && AutofillFeatureFlags.isImproveFillDialogEnabled(); + mFillDialogTimeoutMs = AutofillFeatureFlags.getFillDialogTimeoutMs(); + mFillDialogMinWaitAfterImeAnimationMs = + AutofillFeatureFlags.getFillDialogMinWaitAfterImeAnimationtEndMs(); synchronized (mLock) { mSessionFlags = new SessionFlags(); @@ -1682,6 +1765,13 @@ final class Session public void notifyInlineUiHidden(AutofillId autofillId) { notifyFillUiHidden(autofillId); } + + @Override + public void onInputMethodStartInputView() { + // TODO(b/377868687): This method isn't called when IME doesn't + // support inline suggestion. Handle those cases as well. + onInputMethodStart(); + } }); mMetricsLogger.write( @@ -3044,6 +3134,12 @@ final class Session } } + private void onInputMethodStart() { + synchronized (mLock) { + mLastInputStartTime = SystemClock.elapsedRealtime(); + } + } + private void doStartIntentSender(IntentSender intentSender, Intent intent) { try { synchronized (mLock) { @@ -5407,6 +5503,15 @@ final class Session } } + private void resetImeAnimationState() { + synchronized (mLock) { + mWaitForImeAnimation = false; + mImeAnimationStartTimeMs = DEFAULT_UNASSIGNED_TIME; + mImeAnimationFinishTimeMs = DEFAULT_UNASSIGNED_TIME; + mLastInputStartTime = DEFAULT_UNASSIGNED_TIME; + } + } + @Override public void onFillReady( @NonNull FillResponse response, @@ -5452,18 +5557,24 @@ final class Session final AutofillId[] ids = response.getFillDialogTriggerIds(); if (ids != null && ArrayUtils.contains(ids, filledId)) { - if (requestShowFillDialog(response, filledId, filterText, flags)) { + @ShowFillDialogState int fillDialogState = + requestShowFillDialog(response, filledId, filterText, flags); + if (fillDialogState == SHOW_FILL_DIALOG_YES) { synchronized (mLock) { final ViewState currentView = mViewStates.get(mCurrentViewId); currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN); } - // Just show fill dialog once, so disabled after shown. + // Just show fill dialog once per fill request, so disabled after shown. // Note: Cannot disable before requestShowFillDialog() because the method - // need to check whether fill dialog enabled. + // need to check whether fill dialog is enabled. setFillDialogDisabled(); + resetImeAnimationState(); return; - } else { + } else if (fillDialogState == SHOW_FILL_DIALOG_NO) { + resetImeAnimationState(); setFillDialogDisabled(); + } else { // SHOW_FILL_DIALOG_WAIT + return; } } @@ -5559,7 +5670,20 @@ final class Session } } + private void enableFillDialog() { + if (sVerbose) { + Slog.v(TAG, "Enabling Fill Dialog...."); + } + synchronized (mLock) { + mSessionFlags.mFillDialogDisabled = false; + } + notifyClientFillDialogTriggerIds(null); + } + private void setFillDialogDisabled() { + if (sVerbose) { + Slog.v(TAG, "Disabling Fill Dialog."); + } synchronized (mLock) { mSessionFlags.mFillDialogDisabled = true; } @@ -5577,24 +5701,28 @@ final class Session } } - private boolean requestShowFillDialog( + private @ShowFillDialogState int requestShowFillDialog( FillResponse response, AutofillId filledId, String filterText, int flags) { if (!isFillDialogUiEnabled()) { + // TODO(b/377868687): The above check includes credman fields. We may want to show + // credman fields again. // Unsupported fill dialog UI - if (sDebug) Log.w(TAG, "requestShowFillDialog: fill dialog is disabled"); - return false; + if (sDebug) Log.w(TAG, "requestShowFillDialog(): fill dialog is disabled"); + return SHOW_FILL_DIALOG_NO; } - if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) { - // IME is showing, fallback to normal suggestions UI - if (sDebug) Log.w(TAG, "requestShowFillDialog: IME is showing"); - return false; - } + if (!mImproveFillDialogEnabled) { + if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) { + // IME is showing, fallback to normal suggestions UI + if (sDebug) Log.w(TAG, "requestShowFillDialog(): IME is showing"); + return SHOW_FILL_DIALOG_NO; + } - if (mInlineSessionController.isImeShowing()) { - // IME is showing, fallback to normal suggestions UI - // Note: only work when inline suggestions supported - return false; + if (mInlineSessionController.isImeShowing()) { + // IME is showing, fallback to normal suggestions UI + // Note: only work when inline suggestions supported + return SHOW_FILL_DIALOG_NO; + } } synchronized (mLock) { @@ -5602,29 +5730,84 @@ final class Session || !ArrayUtils.contains(mLastFillDialogTriggerIds, filledId)) { // Last fill dialog triggered ids are changed. if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed."); - return false; + return SHOW_FILL_DIALOG_NO; + } + + if (mImproveFillDialogEnabled && mInlineSessionController.isImeShowing()) { + long currentTimestampMs = SystemClock.elapsedRealtime(); + long durationMs = currentTimestampMs - mLastInputStartTime; + if (sVerbose) { + Log.d(TAG, "IME is showing. Checking for elapsed time "); + Log.d(TAG, "IME is showing. Timestamps start: " + mLastInputStartTime + + " current: " + currentTimestampMs + " duration: " + durationMs + + " mFillDialogTimeoutMs: " + mFillDialogTimeoutMs); + } + + // Following situations can arise wrt IME animation. + // 1. No animation happening (eg IME already animated). In that case, + // mWaitForImeAnimation should be false. This is possible if the IME is already up + // on a field, but the user focusses on another field. Under such condition, + // since IME has already animated, there won't be another animation. However, + // onInputStartInputView is still called. + // 2. Animation is still proceeding. We should wait for animation to finish, + // and then proceed. + // 3. Animation is complete. + if (mWaitForImeAnimation) { + // we need to wait for animation to happen. We can't return from here yet. + // This is the situation #2 described above. + Log.d(TAG, "Waiting for ime animation to complete before showing fill dialog"); + mFillDialogRunnable = createFillDialogEvalRunnable( + response, filledId, filterText, flags); + return SHOW_FILL_DIALOG_WAIT; + } + + // Incorporate situations 1 & 3 discussed above. We calculate the duration from the + // max of start input time or the ime finish time + long effectiveDuration = currentTimestampMs + - Math.max(mLastInputStartTime, mImeAnimationFinishTimeMs); + if (effectiveDuration >= mFillDialogTimeoutMs) { + Log.d(TAG, "Fill dialog not shown since IME has been up for more time than " + + mFillDialogTimeoutMs + "ms"); + return SHOW_FILL_DIALOG_NO; + } else if (effectiveDuration < mFillDialogMinWaitAfterImeAnimationMs) { + // we need to wait for some time after animation ends + Runnable runnable = createFillDialogEvalRunnable( + response, filledId, filterText, flags); + mHandler.postDelayed(runnable, + mFillDialogMinWaitAfterImeAnimationMs - effectiveDuration); + return SHOW_FILL_DIALOG_WAIT; + } } } + showFillDialog(response, filledId, filterText); + return SHOW_FILL_DIALOG_YES; + } + + private Runnable createFillDialogEvalRunnable( + @NonNull FillResponse response, + @NonNull AutofillId filledId, + String filterText, + int flags) { + return () -> { + synchronized (mLock) { + AutofillValue value = AutofillValue.forText(filterText); + onFillReady(response, filledId, value, flags); + } + }; + } + + private void showFillDialog(FillResponse response, AutofillId filledId, String filterText) { Drawable serviceIcon = null; + PresentationStatsEventLogger logger = null; synchronized (mLock) { serviceIcon = getServiceIcon(response); + logger = mPresentationStatsEventLogger; } - getUiForShowing() - .showFillDialog( - filledId, - response, - filterText, - mService.getServicePackageName(), - mComponentName, - serviceIcon, - this, - id, - mCompatMode, - mPresentationStatsEventLogger, - mLock); - return true; + getUiForShowing().showFillDialog(filledId, response, filterText, + mService.getServicePackageName(), mComponentName, serviceIcon, this, + id, mCompatMode, logger, mLock); } /** @@ -7689,6 +7872,30 @@ final class Session mSessionState = STATE_REMOVED; } + @GuardedBy("mLock") + public void notifyImeAnimationStart(long startTimeMs) { + mImeAnimationStartTimeMs = startTimeMs; + mWaitForImeAnimation = true; + } + + @GuardedBy("mLock") + public void notifyImeAnimationEnd(long endTimeMs) { + mImeAnimationFinishTimeMs = endTimeMs; + // Make sure to use mRunnable with synchronized + if (mFillDialogRunnable != null) { + if (sVerbose) { + Log.v(TAG, "Ime animation ended, starting fill dialog."); + } + mHandler.postDelayed(mFillDialogRunnable, mFillDialogMinWaitAfterImeAnimationMs); + mFillDialogRunnable = null; + } else { + if (sVerbose) { + Log.v(TAG, "Ime animation ended, no runnable present."); + } + } + mWaitForImeAnimation = false; + } + void onPendingSaveUi(int operation, @NonNull IBinder token) { getUiForShowing().onPendingSaveUi(operation, token); } diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java index ffc80ee7d710..7287bdd8e34f 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java @@ -409,5 +409,10 @@ public final class InlineFillUi { * Callback to notify inline ui is hidden. */ void notifyInlineUiHidden(@NonNull AutofillId autofillId); + + /** + * Callback to notify input method started. + */ + void onInputMethodStartInputView(); } } diff --git a/services/core/Android.bp b/services/core/Android.bp index 9e645595708c..b3d85f8aac48 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -160,7 +160,6 @@ java_library_static { "android.hardware.vibrator-V3-java", "androidx.annotation_annotation", "app-compat-annotations", - "art_exported_aconfig_flags_lib", "framework-tethering.stubs.module_lib", "keepanno-annotations", "service-art.stubs.system_server", @@ -247,6 +246,7 @@ java_library_static { "locksettings_flags_lib", "profiling_flags_lib", "android.adpf.sessionmanager_aidl-java", + "uprobestats_flags_java_lib", ], javac_shard_size: 50, javacflags: [ diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java index ccc44a41759b..d84a892e4f54 100644 --- a/services/core/java/com/android/server/GestureLauncherService.java +++ b/services/core/java/com/android/server/GestureLauncherService.java @@ -16,9 +16,14 @@ package com.android.server; +import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap; + +import static com.android.hardware.input.Flags.overridePowerKeyBehaviorInFocusedWindow; import static com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis; import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.app.PendingIntent; import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -33,6 +38,7 @@ import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; +import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.WakeLock; @@ -41,10 +47,12 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; +import android.service.quickaccesswallet.QuickAccessWalletClient; import android.util.MutableBoolean; import android.util.Slog; import android.view.KeyEvent; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEvent; @@ -70,7 +78,8 @@ public class GestureLauncherService extends SystemService { * Time in milliseconds in which the power button must be pressed twice so it will be considered * as a camera launch. */ - @VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300; + @VisibleForTesting + static final long POWER_DOUBLE_TAP_MAX_TIME_MS = 300; /** @@ -100,10 +109,23 @@ public class GestureLauncherService extends SystemService { @VisibleForTesting static final int EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX = 5000; - /** - * Number of taps required to launch camera shortcut. - */ - private static final int CAMERA_POWER_TAP_COUNT_THRESHOLD = 2; + /** Indicates camera should be launched on power double tap. */ + @VisibleForTesting static final int LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER = 0; + + /** Indicates wallet should be launched on power double tap. */ + @VisibleForTesting static final int LAUNCH_WALLET_ON_DOUBLE_TAP_POWER = 1; + + /** Number of taps required to launch the double tap shortcut (either camera or wallet). */ + public static final int DOUBLE_POWER_TAP_COUNT_THRESHOLD = 2; + + /** Bundle to send with PendingIntent to grant background activity start privileges. */ + private static final Bundle GRANT_BACKGROUND_START_PRIVILEGES = + ActivityOptions.makeBasic() + .setPendingIntentBackgroundActivityStartMode( + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS) + .toBundle(); + + private final QuickAccessWalletClient mQuickAccessWalletClient; /** The listener that receives the gesture event. */ private final GestureEventListener mGestureListener = new GestureEventListener(); @@ -158,6 +180,9 @@ public class GestureLauncherService extends SystemService { */ private boolean mCameraDoubleTapPowerEnabled; + /** Whether wallet double tap power button gesture is currently enabled. */ + private boolean mWalletDoubleTapPowerEnabled; + /** * Whether emergency gesture is currently enabled */ @@ -204,14 +229,22 @@ public class GestureLauncherService extends SystemService { } } public GestureLauncherService(Context context) { - this(context, new MetricsLogger(), new UiEventLoggerImpl()); + this( + context, + new MetricsLogger(), + QuickAccessWalletClient.create(context), + new UiEventLoggerImpl()); } @VisibleForTesting - GestureLauncherService(Context context, MetricsLogger metricsLogger, + public GestureLauncherService( + Context context, + MetricsLogger metricsLogger, + QuickAccessWalletClient quickAccessWalletClient, UiEventLogger uiEventLogger) { super(context); mContext = context; + mQuickAccessWalletClient = quickAccessWalletClient; mMetricsLogger = metricsLogger; mUiEventLogger = uiEventLogger; } @@ -237,6 +270,9 @@ public class GestureLauncherService extends SystemService { "GestureLauncherService"); updateCameraRegistered(); updateCameraDoubleTapPowerEnabled(); + if (launchWalletOptionOnPowerDoubleTap()) { + updateWalletDoubleTapPowerEnabled(); + } updateEmergencyGestureEnabled(); updateEmergencyGesturePowerButtonCooldownPeriodMs(); @@ -292,6 +328,14 @@ public class GestureLauncherService extends SystemService { } @VisibleForTesting + void updateWalletDoubleTapPowerEnabled() { + boolean enabled = isWalletDoubleTapPowerSettingEnabled(mContext, mUserId); + synchronized (this) { + mWalletDoubleTapPowerEnabled = enabled; + } + } + + @VisibleForTesting void updateEmergencyGestureEnabled() { boolean enabled = isEmergencyGestureSettingEnabled(mContext, mUserId); synchronized (this) { @@ -418,10 +462,33 @@ public class GestureLauncherService extends SystemService { Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0); } + /** Checks if camera should be launched on double press of the power button. */ public static boolean isCameraDoubleTapPowerSettingEnabled(Context context, int userId) { - return isCameraDoubleTapPowerEnabled(context.getResources()) - && (Settings.Secure.getIntForUser(context.getContentResolver(), - Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0); + boolean res; + + if (launchWalletOptionOnPowerDoubleTap()) { + res = isDoubleTapPowerGestureSettingEnabled(context, userId) + && getDoubleTapPowerGestureAction(context, userId) + == LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER; + } else { + // These are legacy settings that will be deprecated once the option to launch both + // wallet and camera has been created. + res = isCameraDoubleTapPowerEnabled(context.getResources()) + && (Settings.Secure.getIntForUser(context.getContentResolver(), + Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0); + } + return res; + } + + /** Checks if wallet should be launched on double tap of the power button. */ + public static boolean isWalletDoubleTapPowerSettingEnabled(Context context, int userId) { + if (!launchWalletOptionOnPowerDoubleTap()) { + return false; + } + + return isDoubleTapPowerGestureSettingEnabled(context, userId) + && getDoubleTapPowerGestureAction(context, userId) + == LAUNCH_WALLET_ON_DOUBLE_TAP_POWER; } public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) { @@ -441,6 +508,28 @@ public class GestureLauncherService extends SystemService { isDefaultEmergencyGestureEnabled(context.getResources()) ? 1 : 0, userId) != 0; } + private static int getDoubleTapPowerGestureAction(Context context, int userId) { + return Settings.Secure.getIntForUser( + context.getContentResolver(), + Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE, + LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER, + userId); + } + + /** Whether the shortcut to launch app on power double press is enabled. */ + private static boolean isDoubleTapPowerGestureSettingEnabled(Context context, int userId) { + return Settings.Secure.getIntForUser( + context.getContentResolver(), + Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, + isDoubleTapConfigEnabled(context.getResources()) ? 1 : 0, + userId) + == 1; + } + + private static boolean isDoubleTapConfigEnabled(Resources resources) { + return resources.getBoolean(R.bool.config_doubleTapPowerGestureEnabled); + } + /** * Gets power button cooldown period in milliseconds after emergency gesture is triggered. The * value is capped at a maximum @@ -494,10 +583,56 @@ public class GestureLauncherService extends SystemService { * Whether GestureLauncherService should be enabled according to system properties. */ public static boolean isGestureLauncherEnabled(Resources resources) { - return isCameraLaunchEnabled(resources) - || isCameraDoubleTapPowerEnabled(resources) - || isCameraLiftTriggerEnabled(resources) - || isEmergencyGestureEnabled(resources); + boolean res = + isCameraLaunchEnabled(resources) + || isCameraLiftTriggerEnabled(resources) + || isEmergencyGestureEnabled(resources); + if (launchWalletOptionOnPowerDoubleTap()) { + res |= isDoubleTapConfigEnabled(resources); + } else { + res |= isCameraDoubleTapPowerEnabled(resources); + } + return res; + } + + /** + * Processes a power key event in GestureLauncherService without performing an action. This + * method is called on every KEYCODE_POWER ACTION_DOWN event and ensures that, even if + * KEYCODE_POWER events are passed to and handled by the app, the GestureLauncherService still + * keeps track of all running KEYCODE_POWER events for its gesture detection and relevant + * actions. + */ + public void processPowerKeyDown(KeyEvent event) { + if (mEmergencyGestureEnabled && mEmergencyGesturePowerButtonCooldownPeriodMs >= 0 + && event.getEventTime() - mLastEmergencyGestureTriggered + < mEmergencyGesturePowerButtonCooldownPeriodMs) { + return; + } + if (event.isLongPress()) { + return; + } + + final long powerTapInterval; + + synchronized (this) { + powerTapInterval = event.getEventTime() - mLastPowerDown; + mLastPowerDown = event.getEventTime(); + if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) { + // Tap too slow, reset consecutive tap counts. + mFirstPowerDown = event.getEventTime(); + mPowerButtonConsecutiveTaps = 1; + mPowerButtonSlowConsecutiveTaps = 1; + } else if (powerTapInterval >= POWER_DOUBLE_TAP_MAX_TIME_MS) { + // Tap too slow for shortcuts + mFirstPowerDown = event.getEventTime(); + mPowerButtonConsecutiveTaps = 1; + mPowerButtonSlowConsecutiveTaps++; + } else if (powerTapInterval > 0) { + // Fast consecutive tap + mPowerButtonConsecutiveTaps++; + mPowerButtonSlowConsecutiveTaps++; + } + } } /** @@ -507,8 +642,8 @@ public class GestureLauncherService extends SystemService { * @param outLaunched true if some action is taken as part of the key intercept (eg, app launch) * @return true if the key down event is intercepted */ - public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive, - MutableBoolean outLaunched) { + public boolean interceptPowerKeyDown( + KeyEvent event, boolean interactive, MutableBoolean outLaunched) { if (mEmergencyGestureEnabled && mEmergencyGesturePowerButtonCooldownPeriodMs >= 0 && event.getEventTime() - mLastEmergencyGestureTriggered < mEmergencyGesturePowerButtonCooldownPeriodMs) { @@ -530,6 +665,7 @@ public class GestureLauncherService extends SystemService { return false; } boolean launchCamera = false; + boolean launchWallet = false; boolean launchEmergencyGesture = false; boolean intercept = false; long powerTapInterval; @@ -541,12 +677,12 @@ public class GestureLauncherService extends SystemService { mFirstPowerDown = event.getEventTime(); mPowerButtonConsecutiveTaps = 1; mPowerButtonSlowConsecutiveTaps = 1; - } else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) { + } else if (powerTapInterval >= POWER_DOUBLE_TAP_MAX_TIME_MS) { // Tap too slow for shortcuts mFirstPowerDown = event.getEventTime(); mPowerButtonConsecutiveTaps = 1; mPowerButtonSlowConsecutiveTaps++; - } else { + } else if (!overridePowerKeyBehaviorInFocusedWindow() || powerTapInterval > 0) { // Fast consecutive tap mPowerButtonConsecutiveTaps++; mPowerButtonSlowConsecutiveTaps++; @@ -586,10 +722,16 @@ public class GestureLauncherService extends SystemService { } } if (mCameraDoubleTapPowerEnabled - && powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - && mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD) { + && powerTapInterval < POWER_DOUBLE_TAP_MAX_TIME_MS + && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD) { launchCamera = true; intercept = interactive; + } else if (launchWalletOptionOnPowerDoubleTap() + && mWalletDoubleTapPowerEnabled + && powerTapInterval < POWER_DOUBLE_TAP_MAX_TIME_MS + && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD) { + launchWallet = true; + intercept = interactive; } } if (mPowerButtonConsecutiveTaps > 1 || mPowerButtonSlowConsecutiveTaps > 1) { @@ -608,6 +750,10 @@ public class GestureLauncherService extends SystemService { (int) powerTapInterval); mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER); } + } else if (launchWallet) { + Slog.i(TAG, "Power button double tap gesture detected, launching wallet. Interval=" + + powerTapInterval + "ms"); + launchWallet = sendGestureTargetActivityPendingIntent(); } else if (launchEmergencyGesture) { Slog.i(TAG, "Emergency gesture detected, launching."); launchEmergencyGesture = handleEmergencyGesture(); @@ -623,11 +769,74 @@ public class GestureLauncherService extends SystemService { mPowerButtonSlowConsecutiveTaps); mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval); - outLaunched.value = launchCamera || launchEmergencyGesture; + outLaunched.value = launchCamera || launchEmergencyGesture || launchWallet; // Intercept power key event if the press is part of a gesture (camera, eGesture) and the // user has completed setup. return intercept && isUserSetupComplete(); } + + /** + * Fetches and sends gestureTargetActivityPendingIntent from QuickAccessWallet, which is a + * specific activity that QuickAccessWalletService has defined to be launch on detection of the + * power button gesture. + */ + private boolean sendGestureTargetActivityPendingIntent() { + boolean userSetupComplete = isUserSetupComplete(); + if (mQuickAccessWalletClient == null + || !mQuickAccessWalletClient.isWalletServiceAvailable()) { + Slog.w(TAG, "QuickAccessWalletService is not available, ignoring wallet gesture."); + return false; + } + + if (!userSetupComplete) { + if (DBG) { + Slog.d(TAG, "userSetupComplete = false, ignoring wallet gesture."); + } + return false; + } + if (DBG) { + Slog.d(TAG, "userSetupComplete = true, performing wallet gesture."); + } + + mQuickAccessWalletClient.getGestureTargetActivityPendingIntent( + getContext().getMainExecutor(), + gesturePendingIntent -> { + if (gesturePendingIntent == null) { + Slog.d(TAG, "getGestureTargetActivityPendingIntent is null."); + sendFallbackPendingIntent(); + return; + } + sendPendingIntentWithBackgroundStartPrivileges(gesturePendingIntent); + }); + return true; + } + + /** + * If gestureTargetActivityPendingIntent is null, this method is invoked to start the activity + * that QuickAccessWalletService has defined to host the Wallet view, which is typically the + * home screen of the Wallet application. + */ + private void sendFallbackPendingIntent() { + mQuickAccessWalletClient.getWalletPendingIntent( + getContext().getMainExecutor(), + walletPendingIntent -> { + if (walletPendingIntent == null) { + Slog.w(TAG, "getWalletPendingIntent returns null. Not launching " + + "anything for wallet."); + return; + } + sendPendingIntentWithBackgroundStartPrivileges(walletPendingIntent); + }); + } + + private void sendPendingIntentWithBackgroundStartPrivileges(PendingIntent pendingIntent) { + try { + pendingIntent.send(GRANT_BACKGROUND_START_PRIVILEGES); + } catch (PendingIntent.CanceledException e) { + Slog.e(TAG, "PendingIntent was canceled", e); + } + } + /** * @return true if camera was launched, false otherwise. */ @@ -700,31 +909,39 @@ public class GestureLauncherService extends SystemService { Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0; } - private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { - mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); - mContext.getContentResolver().unregisterContentObserver(mSettingObserver); - registerContentObservers(); - updateCameraRegistered(); - updateCameraDoubleTapPowerEnabled(); - updateEmergencyGestureEnabled(); - updateEmergencyGesturePowerButtonCooldownPeriodMs(); - } - } - }; - - private final ContentObserver mSettingObserver = new ContentObserver(new Handler()) { - public void onChange(boolean selfChange, android.net.Uri uri, int userId) { - if (userId == mUserId) { - updateCameraRegistered(); - updateCameraDoubleTapPowerEnabled(); - updateEmergencyGestureEnabled(); - updateEmergencyGesturePowerButtonCooldownPeriodMs(); - } - } - }; + private final BroadcastReceiver mUserReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { + mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); + mContext.getContentResolver().unregisterContentObserver(mSettingObserver); + registerContentObservers(); + updateCameraRegistered(); + updateCameraDoubleTapPowerEnabled(); + if (launchWalletOptionOnPowerDoubleTap()) { + updateWalletDoubleTapPowerEnabled(); + } + updateEmergencyGestureEnabled(); + updateEmergencyGesturePowerButtonCooldownPeriodMs(); + } + } + }; + + private final ContentObserver mSettingObserver = + new ContentObserver(new Handler()) { + public void onChange(boolean selfChange, android.net.Uri uri, int userId) { + if (userId == mUserId) { + updateCameraRegistered(); + updateCameraDoubleTapPowerEnabled(); + if (launchWalletOptionOnPowerDoubleTap()) { + updateWalletDoubleTapPowerEnabled(); + } + updateEmergencyGestureEnabled(); + updateEmergencyGesturePowerButtonCooldownPeriodMs(); + } + } + }; private final class GestureEventListener implements SensorEventListener { @Override diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index eba9a25717dd..bd7a0ac55117 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -449,6 +449,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private AtomicBoolean mIsSatelliteEnabled; private AtomicBoolean mWasSatelliteEnabledNotified; + private final int mPid = Process.myPid(); + /** * Per-phone map of precise data connection state. The key of the map is the pair of transport * type and APN setting. This is the cache to prevent redundant callbacks to the listeners. @@ -1441,7 +1443,17 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) { try { - r.callback.onCallStatesChanged(mCallStateLists.get(r.phoneId)); + if (Flags.passCopiedCallStateList()) { + List<CallState> callList; + if (r.callerPid == mPid) { + callList = List.copyOf(mCallStateLists.get(r.phoneId)); + } else { + callList = mCallStateLists.get(r.phoneId); + } + r.callback.onCallStatesChanged(callList); + } else { + r.callback.onCallStatesChanged(mCallStateLists.get(r.phoneId)); + } } catch (RemoteException ex) { remove(r.binder); } @@ -2573,12 +2585,25 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (notifyCallState) { + List<CallState> copyList = null; for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) && idMatch(r, subId, phoneId)) { + // If listener is in the same process, original instance can be passed + // to the listener via AIDL without serialization/de-serialization. We + // will pass the copied list. Since the element is newly created instead + // of modification for the change, we can use shallow copy for this. try { - r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); + if (Flags.passCopiedCallStateList()) { + if (r.callerPid == mPid && copyList == null) { + copyList = List.copyOf(mCallStateLists.get(phoneId)); + } + r.callback.onCallStatesChanged(copyList == null + ? mCallStateLists.get(phoneId) : copyList); + } else { + r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); + } } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2906,13 +2931,21 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("There is no active call to report CallQuality"); return; } - + List<CallState> copyList = null; for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED) && idMatch(r, subId, phoneId)) { try { - r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); + if (Flags.passCopiedCallStateList()) { + if (r.callerPid == mPid && copyList == null) { + copyList = List.copyOf(mCallStateLists.get(phoneId)); + } + r.callback.onCallStatesChanged(copyList == null + ? mCallStateLists.get(phoneId) : copyList); + } else { + r.callback.onCallStatesChanged(mCallStateLists.get(phoneId)); + } } catch (RemoteException ex) { mRemoveList.add(r.binder); } diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index aea24d978bee..c27126a01a32 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1101,9 +1101,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub /** StatsPullAtomCallback for pulling BatteryUsageStats data. */ private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback { - private static final long BATTERY_USAGE_STATS_PER_UID_MAX_STATS_AGE = - TimeUnit.HOURS.toMillis(2); - @Override public int onPullAtom(int atomTag, List<StatsEvent> data) { final BatteryUsageStats bus; @@ -1171,8 +1168,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub .setMinConsumedPowerThreshold(minConsumedPowerThreshold); if (isBatteryUsageStatsAccumulationSupported()) { - query.accumulated() - .setMaxStatsAgeMs(BATTERY_USAGE_STATS_PER_UID_MAX_STATS_AGE); + query.accumulated(); } bus = getBatteryUsageStats(List.of(query.build())).get(0); diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 295e0443371d..06c586f5e9c2 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -3191,7 +3191,7 @@ public class AppOpsService extends IAppOpsService.Stub { resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId, Process.INVALID_UID, null, null, Context.DEVICE_ID_DEFAULT, proxyFlags, !isProxyTrusted, - "proxy " + message, shouldCollectMessage, 1); + "proxy " + message, shouldCollectMessage); if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) { return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag, proxiedPackageName); @@ -3210,20 +3210,7 @@ public class AppOpsService extends IAppOpsService.Stub { return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName, proxiedAttributionTag, proxiedVirtualDeviceId, proxyUid, resolveProxyPackageName, proxyAttributionTag, proxyVirtualDeviceId, proxiedFlags, shouldCollectAsyncNotedOp, - message, shouldCollectMessage, 1); - } - - @Override - public void noteOperationsInBatch(Map batchedNoteOps) { - for (var entry : ((Map<AppOpsManager.NotedOp, Integer>) batchedNoteOps).entrySet()) { - AppOpsManager.NotedOp notedOp = entry.getKey(); - int notedCount = entry.getValue(); - mCheckOpsDelegateDispatcher.noteOperation( - notedOp.getOp(), notedOp.getUid(), notedOp.getPackageName(), - notedOp.getAttributionTag(), notedOp.getVirtualDeviceId(), - notedOp.getShouldCollectAsyncNotedOp(), notedOp.getMessage(), - notedOp.getShouldCollectMessage(), notedCount); - } + message, shouldCollectMessage); } @Override @@ -3241,7 +3228,7 @@ public class AppOpsService extends IAppOpsService.Stub { } return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName, attributionTag, Context.DEVICE_ID_DEFAULT, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, 1); + shouldCollectMessage); } @Override @@ -3250,12 +3237,13 @@ public class AppOpsService extends IAppOpsService.Stub { String message, boolean shouldCollectMessage) { return mCheckOpsDelegateDispatcher.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, 1); + shouldCollectMessage); } private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName, - @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, int notedCount) { + @Nullable String attributionTag, int virtualDeviceId, + boolean shouldCollectAsyncNotedOp, @Nullable String message, + boolean shouldCollectMessage) { String resolvedPackageName; if (!shouldUseNewCheckOp()) { verifyIncomingUid(uid); @@ -3290,14 +3278,14 @@ public class AppOpsService extends IAppOpsService.Stub { return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag, virtualDeviceId, Process.INVALID_UID, null, null, Context.DEVICE_ID_DEFAULT, AppOpsManager.OP_FLAG_SELF, shouldCollectAsyncNotedOp, - message, shouldCollectMessage, notedCount); + message, shouldCollectMessage); } private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName, @Nullable String attributionTag, int virtualDeviceId, int proxyUid, String proxyPackageName, @Nullable String proxyAttributionTag, int proxyVirtualDeviceId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage, int notedCount) { + boolean shouldCollectMessage) { PackageVerificationResult pvr; try { pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName); @@ -3400,11 +3388,11 @@ public class AppOpsService extends IAppOpsService.Stub { virtualDeviceId, flags, AppOpsManager.MODE_ALLOWED); attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, - getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags, notedCount); + getPersistentId(proxyVirtualDeviceId), uidState.getState(), flags); if (shouldCollectAsyncNotedOp) { collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message, - shouldCollectMessage, notedCount); + shouldCollectMessage); } return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag, @@ -3563,7 +3551,7 @@ public class AppOpsService extends IAppOpsService.Stub { */ private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode, @Nullable String attributionTag, @OpFlags int flags, @NonNull String message, - boolean shouldCollectMessage, int notedCount) { + boolean shouldCollectMessage) { Objects.requireNonNull(message); int callingUid = Binder.getCallingUid(); @@ -3571,51 +3559,42 @@ public class AppOpsService extends IAppOpsService.Stub { final long token = Binder.clearCallingIdentity(); try { synchronized (this) { + Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); + + RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); + AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid, + attributionTag, message, System.currentTimeMillis()); + final boolean[] wasNoteForwarded = {false}; + if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) != 0 && shouldCollectMessage) { reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, attributionTag, message); } - Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid); - RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key); - if (callbacks == null) { - return; - } - - final boolean[] wasNoteForwarded = {false}; - if (Flags.rateLimitBatchedNoteOpAsyncCallbacksEnabled()) { - notedCount = 1; - } - - for (int i = 0; i < notedCount; i++) { - AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid, - attributionTag, message, System.currentTimeMillis()); - wasNoteForwarded[0] = false; + if (callbacks != null) { callbacks.broadcast((cb) -> { try { cb.opNoted(asyncNotedOp); wasNoteForwarded[0] = true; } catch (RemoteException e) { Slog.e(TAG, - "Could not forward noteOp of " + opCode + " to " - + packageName + "Could not forward noteOp of " + opCode + " to " + packageName + "/" + uid + "(" + attributionTag + ")", e); } }); + } - if (!wasNoteForwarded[0]) { - ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get( - key); - if (unforwardedOps == null) { - unforwardedOps = new ArrayList<>(1); - mUnforwardedAsyncNotedOps.put(key, unforwardedOps); - } + if (!wasNoteForwarded[0]) { + ArrayList<AsyncNotedAppOp> unforwardedOps = mUnforwardedAsyncNotedOps.get(key); + if (unforwardedOps == null) { + unforwardedOps = new ArrayList<>(1); + mUnforwardedAsyncNotedOps.put(key, unforwardedOps); + } - unforwardedOps.add(asyncNotedOp); - if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) { - unforwardedOps.remove(0); - } + unforwardedOps.add(asyncNotedOp); + if (unforwardedOps.size() > MAX_UNFORWARDED_OPS) { + unforwardedOps.remove(0); } } } @@ -4047,7 +4026,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (shouldCollectAsyncNotedOp && !isRestricted) { collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF, - message, shouldCollectMessage, 1); + message, shouldCollectMessage); } return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag, @@ -7595,36 +7574,34 @@ public class AppOpsService extends IAppOpsService.Stub { public SyncNotedAppOp noteOperation(int code, int uid, String packageName, String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - String message, boolean shouldCollectMessage, int notedCount) { + String message, boolean shouldCollectMessage) { if (mPolicy != null) { if (mCheckOpsDelegate != null) { return mPolicy.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, notedCount, this::noteDelegateOperationImpl + shouldCollectMessage, this::noteDelegateOperationImpl ); } else { return mPolicy.noteOperation(code, uid, packageName, attributionTag, virtualDeviceId, shouldCollectAsyncNotedOp, message, - shouldCollectMessage, notedCount, AppOpsService.this::noteOperationImpl + shouldCollectMessage, AppOpsService.this::noteOperationImpl ); } } else if (mCheckOpsDelegate != null) { return noteDelegateOperationImpl(code, uid, packageName, attributionTag, - virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - notedCount); + virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } return noteOperationImpl(code, uid, packageName, attributionTag, - virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - notedCount); + virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage); } private SyncNotedAppOp noteDelegateOperationImpl(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage, int notedCount) { + boolean shouldCollectMessage) { return mCheckOpsDelegate.noteOperation(code, uid, packageName, featureId, virtualDeviceId, shouldCollectAsyncNotedOp, message, shouldCollectMessage, - notedCount, AppOpsService.this::noteOperationImpl + AppOpsService.this::noteOperationImpl ); } diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java index 4d114b4ad4ac..314664b0a79d 100644 --- a/services/core/java/com/android/server/appop/AttributedOp.java +++ b/services/core/java/com/android/server/appop/AttributedOp.java @@ -100,12 +100,10 @@ final class AttributedOp { * @param proxyDeviceId The device Id of the proxy * @param uidState UID state of the app noteOp/startOp was called for * @param flags OpFlags of the call - * @param accessCount The number of times the op is accessed */ public void accessed(int proxyUid, @Nullable String proxyPackageName, @Nullable String proxyAttributionTag, @Nullable String proxyDeviceId, - @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags, - int accessCount) { + @AppOpsManager.UidState int uidState, @AppOpsManager.OpFlags int flags) { long accessTime = System.currentTimeMillis(); accessed(accessTime, -1, proxyUid, proxyPackageName, proxyAttributionTag, proxyDeviceId, uidState, flags); @@ -113,7 +111,7 @@ final class AttributedOp { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, uidState, flags, accessTime, AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE, - DiscreteRegistry.ACCESS_TYPE_NOTE_OP, accessCount); + DiscreteRegistry.ACCESS_TYPE_NOTE_OP); } /** @@ -257,7 +255,7 @@ final class AttributedOp { if (isStarted) { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, uidState, flags, startTime, - attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP, 1); + attributionFlags, attributionChainId, DiscreteRegistry.ACCESS_TYPE_START_OP); } } @@ -453,7 +451,7 @@ final class AttributedOp { mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName, persistentDeviceId, tag, event.getUidState(), event.getFlags(), startTime, event.getAttributionFlags(), - event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP, 1); + event.getAttributionChainId(), DiscreteRegistry.ACCESS_TYPE_RESUME_OP); if (shouldSendActive) { mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName, tag, event.getVirtualDeviceId(), true, diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 5e67f26ba1f6..6b0253864e2b 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -475,7 +475,7 @@ final class HistoricalRegistry { @NonNull String deviceId, @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags, long accessTime, @AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId, - @DiscreteRegistry.AccessType int accessType, int accessCount) { + @DiscreteRegistry.AccessType int accessType) { synchronized (mInMemoryLock) { if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) { if (!isPersistenceInitializedMLocked()) { @@ -484,7 +484,7 @@ final class HistoricalRegistry { } getUpdatedPendingHistoricalOpsMLocked( System.currentTimeMillis()).increaseAccessCount(op, uid, packageName, - attributionTag, uidState, flags, accessCount); + attributionTag, uidState, flags, 1); mDiscreteRegistry.recordDiscreteAccess(uid, packageName, deviceId, op, attributionTag, flags, uidState, accessTime, -1, attributionFlags, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 5928f8105cdf..09b8e212bfad 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4684,6 +4684,12 @@ public class AudioService extends IAudioService.Stub switch (mode) { case AudioSystem.MODE_IN_COMMUNICATION: case AudioSystem.MODE_IN_CALL: + // TODO(b/382704431): remove to allow STREAM_VOICE_CALL to drive abs volume + // over A2DP + if (getDeviceForStream(AudioSystem.STREAM_VOICE_CALL) + == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) { + return AudioSystem.STREAM_MUSIC; + } return AudioSystem.STREAM_VOICE_CALL; case AudioSystem.MODE_CALL_SCREENING: case AudioSystem.MODE_COMMUNICATION_REDIRECT: @@ -4695,15 +4701,20 @@ public class AudioService extends IAudioService.Stub // other conditions will influence the stream type choice, read on... break; } - if (voiceActivityCanOverride - && mVoicePlaybackActive.get()) { + + if (voiceActivityCanOverride && mVoicePlaybackActive.get()) { + // TODO(b/382704431): remove to allow STREAM_VOICE_CALL to drive abs volume over A2DP + if (getDeviceForStream(AudioSystem.STREAM_VOICE_CALL) + == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) { + return AudioSystem.STREAM_MUSIC; + } return AudioSystem.STREAM_VOICE_CALL; } return AudioSystem.STREAM_MUSIC; } - private AtomicBoolean mVoicePlaybackActive = new AtomicBoolean(false); - private AtomicBoolean mMediaPlaybackActive = new AtomicBoolean(false); + private final AtomicBoolean mVoicePlaybackActive = new AtomicBoolean(false); + private final AtomicBoolean mMediaPlaybackActive = new AtomicBoolean(false); private final IPlaybackConfigDispatcher mPlaybackActivityMonitor = new IPlaybackConfigDispatcher.Stub() { @@ -4923,7 +4934,7 @@ public class AudioService extends IAudioService.Stub private void onUpdateContextualVolumes() { final int streamType = getBluetoothContextualVolumeStream(); - Log.i(TAG, + Slog.i(TAG, "onUpdateContextualVolumes: absolute volume driving streams " + streamType + " avrcp supported: " + mAvrcpAbsVolSupported); synchronized (mCachedAbsVolDrivingStreamsLock) { @@ -4932,7 +4943,7 @@ public class AudioService extends IAudioService.Stub if (absDev == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) { enabled = mAvrcpAbsVolSupported; if (!enabled) { - Log.w(TAG, "Updating avrcp not supported in onUpdateContextualVolumes"); + Slog.w(TAG, "Updating avrcp not supported in onUpdateContextualVolumes"); } } if (stream != streamType) { @@ -4960,7 +4971,7 @@ public class AudioService extends IAudioService.Stub return; } if (absVolumeDevices.size() > 1) { - Log.w(TAG, "onUpdateContextualVolumes too many active devices: " + Slog.w(TAG, "onUpdateContextualVolumes too many active devices: " + absVolumeDevices.stream().map(AudioSystem::getOutputDeviceName) .collect(Collectors.joining(",")) + ", for stream: " + streamType); @@ -4971,7 +4982,7 @@ public class AudioService extends IAudioService.Stub final int index = getStreamVolume(streamType, device); if (DEBUG_VOL) { - Log.i(TAG, "onUpdateContextualVolumes streamType: " + streamType + Slog.i(TAG, "onUpdateContextualVolumes streamType: " + streamType + ", device: " + AudioSystem.getOutputDeviceName(device) + ", index: " + index); } diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java index 251344395ae3..5d9db65fe2b2 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java @@ -19,17 +19,19 @@ package com.android.server.devicestate; import static android.Manifest.permission.CONTROL_DEVICE_STATE; import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED; -import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN; -import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN; import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FEATURE_DUAL_DISPLAY; import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FEATURE_REAR_DISPLAY; import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY; import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN; +import static android.frameworks.devicestate.DeviceStateConfiguration.DeviceStatePropertyValue.FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT; import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY; +import static android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT; import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY; import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY; +import static android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED; import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_AVAILABLE_FOR_APP_REQUEST; import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_OVERRIDE_REQUESTS; import static android.hardware.devicestate.DeviceState.PROPERTY_POLICY_CANCEL_WHEN_REQUESTER_NOT_ON_TOP; @@ -98,7 +100,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.WeakHashMap; @@ -854,7 +855,7 @@ public final class DeviceStateManagerService extends SystemService { } } - private void requestStateInternal(int state, int flags, int callingPid, int callingUid, + private void requestStateInternal(int requestedState, int flags, int callingPid, int callingUid, @NonNull IBinder token, boolean hasControlDeviceStatePermission) { synchronized (mLock) { final ProcessRecord processRecord = mProcessRecords.get(callingPid); @@ -869,19 +870,30 @@ public final class DeviceStateManagerService extends SystemService { + " token: " + token); } - final Optional<DeviceState> deviceState = getStateLocked(state); - if (!deviceState.isPresent()) { - throw new IllegalArgumentException("Requested state: " + state + final Optional<DeviceState> requestedDeviceState = getStateLocked(requestedState); + if (requestedDeviceState.isEmpty()) { + throw new IllegalArgumentException("Requested state: " + requestedState + " is not supported."); } - OverrideRequest request = new OverrideRequest(token, callingPid, callingUid, - deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE); + final OverrideRequest request = new OverrideRequest(token, callingPid, callingUid, + requestedDeviceState.get(), flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE); if (Flags.deviceStatePropertyMigration()) { - // If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay - if (!hasControlDeviceStatePermission && deviceState.get().hasProperty( - PROPERTY_FEATURE_REAR_DISPLAY)) { + final boolean isRequestingRdm = requestedDeviceState.get() + .hasProperty(PROPERTY_FEATURE_REAR_DISPLAY); + final boolean isRequestingRdmOuterDefault = requestedDeviceState.get() + .hasProperty(PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT); + + final boolean isDeviceClosed = mCommittedState.isEmpty() ? false + : mCommittedState.get().hasProperty( + PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED); + + final boolean shouldShowRdmEduDialog = isRequestingRdm && shouldShowRdmEduDialog( + hasControlDeviceStatePermission, isRequestingRdmOuterDefault, + isDeviceClosed); + + if (shouldShowRdmEduDialog) { showRearDisplayEducationalOverlayLocked(request); } else { mOverrideRequestController.addRequest(request); @@ -889,7 +901,7 @@ public final class DeviceStateManagerService extends SystemService { } else { // If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay if (!hasControlDeviceStatePermission && mRearDisplayState != null - && state == mRearDisplayState.getIdentifier()) { + && requestedState == mRearDisplayState.getIdentifier()) { showRearDisplayEducationalOverlayLocked(request); } else { mOverrideRequestController.addRequest(request); @@ -899,6 +911,28 @@ public final class DeviceStateManagerService extends SystemService { } /** + * Determines if the system should show an educational dialog before entering rear display mode + * @param hasControlDeviceStatePermission If the app has the CONTROL_DEVICE_STATE permission, we + * don't need to show the overlay + * @param requestingRdmOuterDefault True if the system is requesting + * PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT + * @param isDeviceClosed True if the device is closed (folded) when the request was made + */ + @VisibleForTesting + static boolean shouldShowRdmEduDialog(boolean hasControlDeviceStatePermission, + boolean requestingRdmOuterDefault, boolean isDeviceClosed) { + if (hasControlDeviceStatePermission) { + return false; + } + + if (requestingRdmOuterDefault) { + return isDeviceClosed; + } else { + return true; + } + } + + /** * If we get a request to enter rear display mode, we need to display an educational * overlay to let the user know what will happen. This calls into the * {@link StatusBarManagerInternal} to notify SystemUI to display the educational dialog. 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 4a533f42ffea..ef73463122ff 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java @@ -186,7 +186,9 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /** Invoked when the underlying binder of this broker has died at the client process. */ @Override public void binderDied() { - unregister(); + if (mIsRegistered.get()) { + unregister(); + } } /* package */ void attachDeathRecipient() throws RemoteException { 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 8c5095f35f0d..155a92a21368 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java @@ -65,8 +65,12 @@ import java.util.concurrent.ConcurrentHashMap; /** Variables for managing endpoint ID creation */ private final Object mEndpointLock = new Object(); + /** + * The next available endpoint ID to register. Per EndpointId.aidl definition, dynamic + * endpoint IDs must have the left-most bit as 1, and the values 0/-1 are invalid. + */ @GuardedBy("mEndpointLock") - private long mNextEndpointId = 0; + private long mNextEndpointId = -2; /** The minimum session ID reservable by endpoints (retrieved from HAL) */ private final int mMinSessionId; @@ -282,10 +286,10 @@ import java.util.concurrent.ConcurrentHashMap; /** @return an available endpoint ID */ private long getNewEndpointId() { synchronized (mEndpointLock) { - if (mNextEndpointId == Long.MAX_VALUE) { + if (mNextEndpointId >= 0) { throw new IllegalStateException("Too many endpoints connected"); } - return mNextEndpointId++; + return mNextEndpointId--; } } 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 0b47a61341f7..d916eda693d8 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -798,7 +798,7 @@ public class ContextHubService extends IContextHubService.Stub { throws RemoteException { super.registerEndpoint_enforcePermission(); if (mEndpointManager == null) { - Log.e(TAG, "ContextHubService.registerEndpoint: endpoint manager failed to initialize"); + Log.e(TAG, "Endpoint manager failed to initialize"); throw new UnsupportedOperationException("Endpoint registration is not supported"); } return mEndpointManager.registerEndpoint(pendingHubEndpointInfo, callback); @@ -809,7 +809,8 @@ public class ContextHubService extends IContextHubService.Stub { public void registerEndpointDiscoveryCallbackId( long endpointId, IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.registerEndpointDiscoveryCallbackId_enforcePermission(); - // TODO(b/375487784): Implement this + checkEndpointDiscoveryPreconditions(); + mHubInfoRegistry.registerEndpointDiscoveryCallback(endpointId, callback); } @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @@ -818,7 +819,8 @@ public class ContextHubService extends IContextHubService.Stub { String serviceDescriptor, IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.registerEndpointDiscoveryCallbackDescriptor_enforcePermission(); - // TODO(b/375487784): Implement this + checkEndpointDiscoveryPreconditions(); + mHubInfoRegistry.registerEndpointDiscoveryCallback(serviceDescriptor, callback); } @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) @@ -826,7 +828,15 @@ public class ContextHubService extends IContextHubService.Stub { public void unregisterEndpointDiscoveryCallback(IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.unregisterEndpointDiscoveryCallback_enforcePermission(); - // TODO(b/375487784): Implement this + checkEndpointDiscoveryPreconditions(); + mHubInfoRegistry.unregisterEndpointDiscoveryCallback(callback); + } + + private void checkEndpointDiscoveryPreconditions() { + if (mHubInfoRegistry == null) { + Log.e(TAG, "Hub endpoint registry failed to initialize"); + throw new UnsupportedOperationException("Endpoint discovery is not supported"); + } } /** diff --git a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java index b91249204199..6f5f191849e2 100644 --- a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java +++ b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java @@ -18,7 +18,9 @@ package com.android.server.location.contexthub; import android.hardware.contexthub.HubEndpointInfo; import android.hardware.contexthub.HubServiceInfo; +import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback; import android.hardware.location.HubInfo; +import android.os.DeadObjectException; import android.os.RemoteException; import android.util.ArrayMap; import android.util.IndentingPrintWriter; @@ -29,6 +31,9 @@ import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.BiConsumer; class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycleCallback { private static final String TAG = "HubInfoRegistry"; @@ -43,6 +48,56 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl private final ArrayMap<HubEndpointInfo.HubEndpointIdentifier, HubEndpointInfo> mHubEndpointInfos = new ArrayMap<>(); + /** + * A wrapper class that is used to store arguments to + * ContextHubManager.registerEndpointCallback. + */ + private static class DiscoveryCallback { + private final IContextHubEndpointDiscoveryCallback mCallback; + private final Optional<Long> mEndpointId; + private final Optional<String> mServiceDescriptor; + + DiscoveryCallback(IContextHubEndpointDiscoveryCallback callback, long endpointId) { + mCallback = callback; + mEndpointId = Optional.of(endpointId); + mServiceDescriptor = Optional.empty(); + } + + DiscoveryCallback(IContextHubEndpointDiscoveryCallback callback, String serviceDescriptor) { + mCallback = callback; + mEndpointId = Optional.empty(); + mServiceDescriptor = Optional.of(serviceDescriptor); + } + + public IContextHubEndpointDiscoveryCallback getCallback() { + return mCallback; + } + + /** + * @param info The hub endpoint info to check + * @return true if info matches + */ + public boolean isMatch(HubEndpointInfo info) { + if (mEndpointId.isPresent()) { + return mEndpointId.get() == info.getIdentifier().getEndpoint(); + } + if (mServiceDescriptor.isPresent()) { + for (HubServiceInfo serviceInfo : info.getServiceInfoCollection()) { + if (mServiceDescriptor.get().equals(serviceInfo.getServiceDescriptor())) { + return true; + } + } + } + return false; + } + } + + /* The list of discovery callbacks registered with the service */ + @GuardedBy("mCallbackLock") + private final List<DiscoveryCallback> mEndpointDiscoveryCallbacks = new ArrayList<>(); + + private final Object mCallbackLock = new Object(); + HubInfoRegistry(IContextHubWrapper contextHubWrapper) { mContextHubWrapper = contextHubWrapper; refreshCachedHubs(); @@ -109,16 +164,50 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo); } } + + invokeForMatchingEndpoints( + endpointInfos, + (cb, infoList) -> { + try { + cb.onEndpointsStarted(infoList); + } catch (RemoteException e) { + if (e instanceof DeadObjectException) { + Log.w(TAG, "onEndpointStarted: callback died, unregistering"); + unregisterEndpointDiscoveryCallback(cb); + } else { + Log.e(TAG, "Exception while calling onEndpointsStarted", e); + } + } + }); } @Override public void onEndpointStopped( HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason) { + ArrayList<HubEndpointInfo> removedInfoList = new ArrayList<>(); synchronized (mLock) { for (HubEndpointInfo.HubEndpointIdentifier endpointId : endpointIds) { - mHubEndpointInfos.remove(endpointId); + HubEndpointInfo info = mHubEndpointInfos.remove(endpointId); + if (info != null) { + removedInfoList.add(info); + } } } + + invokeForMatchingEndpoints( + removedInfoList.toArray(new HubEndpointInfo[removedInfoList.size()]), + (cb, infoList) -> { + try { + cb.onEndpointsStopped(infoList, reason); + } catch (RemoteException e) { + if (e instanceof DeadObjectException) { + Log.w(TAG, "onEndpointStopped: callback died, unregistering"); + unregisterEndpointDiscoveryCallback(cb); + } else { + Log.e(TAG, "Exception while calling onEndpointsStopped", e); + } + } + }); } /** Return a list of {@link HubEndpointInfo} that represents endpoints with the matching id. */ @@ -151,6 +240,77 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl return searchResult; } + /* package */ + void registerEndpointDiscoveryCallback( + long endpointId, IContextHubEndpointDiscoveryCallback callback) { + Objects.requireNonNull(callback, "callback cannot be null"); + synchronized (mCallbackLock) { + checkCallbackAlreadyRegistered(callback); + mEndpointDiscoveryCallbacks.add(new DiscoveryCallback(callback, endpointId)); + } + } + + /* package */ + void registerEndpointDiscoveryCallback( + String serviceDescriptor, IContextHubEndpointDiscoveryCallback callback) { + Objects.requireNonNull(callback, "callback cannot be null"); + synchronized (mCallbackLock) { + checkCallbackAlreadyRegistered(callback); + mEndpointDiscoveryCallbacks.add(new DiscoveryCallback(callback, serviceDescriptor)); + } + } + + /* package */ + void unregisterEndpointDiscoveryCallback(IContextHubEndpointDiscoveryCallback callback) { + Objects.requireNonNull(callback, "callback cannot be null"); + synchronized (mCallbackLock) { + for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { + if (discoveryCallback.getCallback().asBinder() == callback.asBinder()) { + mEndpointDiscoveryCallbacks.remove(discoveryCallback); + break; + } + } + } + } + + private void checkCallbackAlreadyRegistered( + IContextHubEndpointDiscoveryCallback callback) { + synchronized (mCallbackLock) { + for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { + if (discoveryCallback.mCallback.asBinder() == callback.asBinder()) { + throw new IllegalArgumentException("Callback is already registered"); + } + } + } + } + + /** + * Iterates through all registered discovery callbacks and invokes a given callback for those + * that match the endpoints the callback is targeted for. + * + * @param endpointInfos The list of endpoint infos to check for a match. + * @param consumer The callback to invoke, which consumes the callback object and the list of + * matched endpoint infos. + */ + private void invokeForMatchingEndpoints( + HubEndpointInfo[] endpointInfos, + BiConsumer<IContextHubEndpointDiscoveryCallback, HubEndpointInfo[]> consumer) { + synchronized (mCallbackLock) { + for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { + ArrayList<HubEndpointInfo> infoList = new ArrayList<>(); + for (HubEndpointInfo endpointInfo : endpointInfos) { + if (discoveryCallback.isMatch(endpointInfo)) { + infoList.add(endpointInfo); + } + } + + consumer.accept( + discoveryCallback.getCallback(), + infoList.toArray(new HubEndpointInfo[infoList.size()])); + } + } + } + void dump(IndentingPrintWriter ipw) { synchronized (mLock) { dumpLocked(ipw); diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java index 6d54be84d5e5..d78e98bf8e61 100644 --- a/services/core/java/com/android/server/pm/BroadcastHelper.java +++ b/services/core/java/com/android/server/pm/BroadcastHelper.java @@ -78,6 +78,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.function.BiFunction; +import java.util.function.Supplier; /** * Helper class to send broadcasts for various situations. @@ -216,7 +217,7 @@ public final class BroadcastHelper { filterExtrasForReceiver, bOptions); } - void sendResourcesChangedBroadcast(@NonNull Computer snapshot, + void sendResourcesChangedBroadcast(@NonNull Supplier<Computer> snapshotSupplier, boolean mediaStatus, boolean replacing, @NonNull String[] pkgNames, @@ -236,7 +237,7 @@ public final class BroadcastHelper { null /* targetPkg */, null /* finishedReceiver */, null /* userIds */, null /* instantUserIds */, null /* broadcastAllowList */, (callingUid, intentExtras) -> filterExtrasChangedPackageList( - snapshot, callingUid, intentExtras), + snapshotSupplier, callingUid, intentExtras), null /* bOptions */, null /* requiredPermissions */); } @@ -544,7 +545,7 @@ public final class BroadcastHelper { }); } - void sendPostInstallBroadcasts(@NonNull Computer snapshot, + void sendPostInstallBroadcasts(@NonNull Supplier<Computer> snapshotSupplier, @NonNull InstallRequest request, @NonNull String packageName, @NonNull String requiredPermissionControllerPackage, @@ -567,8 +568,8 @@ public final class BroadcastHelper { final int[] uids = new int[]{request.getRemovedInfo().mUid}; notifyResourcesChanged( false /* mediaStatus */, true /* replacing */, pkgNames, uids); - sendResourcesChangedBroadcast( - snapshot, false /* mediaStatus */, true /* replacing */, pkgNames, uids); + sendResourcesChangedBroadcast(snapshotSupplier, + false /* mediaStatus */, true /* replacing */, pkgNames, uids); } sendPackageRemovedBroadcasts( request.getRemovedInfo(), packageSender, isKillApp, false /*removedBySystem*/, @@ -608,6 +609,7 @@ public final class BroadcastHelper { null /* broadcastAllowList */, null); } + final Computer snapshot = snapshotSupplier.get(); // Send installed broadcasts if the package is not a static shared lib. if (staticSharedLibraryName == null) { // Send PACKAGE_ADDED broadcast for users that see the package for the first time @@ -732,7 +734,7 @@ public final class BroadcastHelper { if (!isArchived) { final String[] pkgNames = new String[]{packageName}; final int[] uids = new int[]{request.getPkg().getUid()}; - sendResourcesChangedBroadcast(snapshot, + sendResourcesChangedBroadcast(snapshotSupplier, true /* mediaStatus */, true /* replacing */, pkgNames, uids); notifyResourcesChanged(true /* mediaStatus */, true /* replacing */, pkgNames, uids); @@ -860,8 +862,8 @@ public final class BroadcastHelper { * access all the packages in the extras. */ @Nullable - private static Bundle filterExtrasChangedPackageList(@NonNull Computer snapshot, int callingUid, - @NonNull Bundle extras) { + private static Bundle filterExtrasChangedPackageList( + @NonNull Supplier<Computer> snapshotSupplier, int callingUid, @NonNull Bundle extras) { if (UserHandle.isCore(callingUid)) { // see all return extras; @@ -873,6 +875,7 @@ public final class BroadcastHelper { final int userId = extras.getInt( Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(callingUid)); final int[] uids = extras.getIntArray(Intent.EXTRA_CHANGED_UID_LIST); + final Computer snapshot = snapshotSupplier.get(); final Pair<String[], int[]> filteredPkgs = filterPackages(snapshot, pkgs, uids, callingUid, userId); if (ArrayUtils.isEmpty(filteredPkgs.first)) { @@ -952,10 +955,12 @@ public final class BroadcastHelper { final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY; final SparseArray<int[]> broadcastAllowList = isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds); + final String[] sharedUserPackages = + snapshot.getSharedUserPackagesForPackage(packageName, userId); mHandler.post(() -> sendPackageChangedBroadcastInternal( packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, setting.getPkg(), - snapshot.getSharedUserPackagesForPackage(packageName, userId))); + sharedUserPackages)); mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler); } @@ -1120,7 +1125,7 @@ public final class BroadcastHelper { * @param uidList The uids of packages which have suspension changes. * @param userId The user where packages reside. */ - void sendPackagesSuspendedOrUnsuspendedForUser(@NonNull Computer snapshot, + void sendPackagesSuspendedOrUnsuspendedForUser(@NonNull Supplier<Computer> snapshotSupplier, @NonNull String intent, @NonNull String[] pkgList, @NonNull int[] uidList, @@ -1138,7 +1143,7 @@ public final class BroadcastHelper { .toBundle(); BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver = (callingUid, intentExtras) -> BroadcastHelper.filterExtrasChangedPackageList( - snapshot, callingUid, intentExtras); + snapshotSupplier, callingUid, intentExtras); mHandler.post(() -> sendPackageBroadcast(intent, null /* pkg */, extras, flags, null /* targetPkg */, null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */, null /* broadcastAllowList */, @@ -1148,7 +1153,7 @@ public final class BroadcastHelper { null /* instantUserIds */, null /* broadcastAllowList */, filterExtrasForReceiver); } - void sendMyPackageSuspendedOrUnsuspended(@NonNull Computer snapshot, + void sendMyPackageSuspendedOrUnsuspended(@NonNull Supplier<Computer> snapshotSupplier, @NonNull String[] affectedPackages, boolean suspended, int userId) { @@ -1163,6 +1168,7 @@ public final class BroadcastHelper { return; } final int[] targetUserIds = new int[] {userId}; + final Computer snapshot = snapshotSupplier.get(); for (String packageName : affectedPackages) { final Bundle appExtras = suspended ? SuspendPackageHelper.getSuspendedPackageAppExtras( @@ -1192,7 +1198,7 @@ public final class BroadcastHelper { * @param uidList The uids of packages which have suspension changes. * @param userId The user where packages reside. */ - void sendDistractingPackagesChanged(@NonNull Computer snapshot, + void sendDistractingPackagesChanged(@NonNull Supplier<Computer> snapshotSupplier, @NonNull String[] pkgList, @NonNull int[] uidList, int userId, @@ -1208,11 +1214,11 @@ public final class BroadcastHelper { null /* finishedReceiver */, new int[]{userId}, null /* instantUserIds */, null /* broadcastAllowList */, (callingUid, intentExtras) -> filterExtrasChangedPackageList( - snapshot, callingUid, intentExtras), + snapshotSupplier, callingUid, intentExtras), null /* bOptions */, null /* requiredPermissions */)); } - void sendResourcesChangedBroadcastAndNotify(@NonNull Computer snapshot, + void sendResourcesChangedBroadcastAndNotify(@NonNull Supplier<Computer> snapshotSupplier, boolean mediaStatus, boolean replacing, @NonNull ArrayList<AndroidPackage> packages) { @@ -1224,7 +1230,7 @@ public final class BroadcastHelper { packageNames[i] = pkg.getPackageName(); packageUids[i] = pkg.getUid(); } - sendResourcesChangedBroadcast(snapshot, mediaStatus, + sendResourcesChangedBroadcast(snapshotSupplier, mediaStatus, replacing, packageNames, packageUids); notifyResourcesChanged(mediaStatus, replacing, packageNames, packageUids); } diff --git a/services/core/java/com/android/server/pm/DistractingPackageHelper.java b/services/core/java/com/android/server/pm/DistractingPackageHelper.java index c5ec73b4e2b8..c4e981d487bc 100644 --- a/services/core/java/com/android/server/pm/DistractingPackageHelper.java +++ b/services/core/java/com/android/server/pm/DistractingPackageHelper.java @@ -123,7 +123,7 @@ public final class DistractingPackageHelper { if (!changedPackagesList.isEmpty()) { final String[] changedPackages = changedPackagesList.toArray( new String[changedPackagesList.size()]); - mBroadcastHelper.sendDistractingPackagesChanged(mPm.snapshotComputer(), + mBroadcastHelper.sendDistractingPackagesChanged(mPm::snapshotComputer, changedPackages, changedUids.toArray(), userId, restrictionFlags); mPm.scheduleWritePackageRestrictions(userId); } @@ -198,7 +198,7 @@ public final class DistractingPackageHelper { if (!changedPackages.isEmpty()) { final String[] packageArray = changedPackages.toArray( new String[changedPackages.size()]); - mBroadcastHelper.sendDistractingPackagesChanged(mPm.snapshotComputer(), + mBroadcastHelper.sendDistractingPackagesChanged(mPm::snapshotComputer, packageArray, changedUids.toArray(), userId, RESTRICTION_NONE); mPm.scheduleWritePackageRestrictions(userId); } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 69c6ce8ea0cd..183ceaecb70e 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -3084,7 +3084,7 @@ final class InstallPackageHelper { mPm.mProcessLoggingHandler.invalidateBaseApkHash(request.getPkg().getBaseApkPath()); } - mBroadcastHelper.sendPostInstallBroadcasts(mPm.snapshotComputer(), request, packageName, + mBroadcastHelper.sendPostInstallBroadcasts(mPm::snapshotComputer, request, packageName, mPm.mRequiredPermissionControllerPackage, mPm.mRequiredVerifierPackages, mPm.mRequiredInstallerPackage, /* packageSender= */ mPm, launchedForRestore, killApp, update, archived); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 65bb701563a8..fd0a90c5833a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -4063,6 +4063,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService mPendingBroadcasts.remove(userId, packageName); } else { mPendingBroadcasts.addComponent(userId, packageName, componentName); + Trace.instant(Trace.TRACE_TAG_PACKAGE_MANAGER, "setEnabledSetting broadcast: " + + componentName + ": " + setting.getEnabledState()); scheduleBroadcastMessage = true; } } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 975758241e77..7af39f74d0d6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -749,7 +749,7 @@ public class PackageManagerServiceUtils { null /*abiOverride*/, false /*isIncremental*/); } catch (IOException e) { logCriticalInfo(Log.ERROR, "Failed to extract native libraries" - + "; pkg: " + packageName); + + "; pkg: " + packageName + "; err: " + e.getMessage()); return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } finally { IoUtils.closeQuietly(handle); diff --git a/services/core/java/com/android/server/pm/SaferIntentUtils.java b/services/core/java/com/android/server/pm/SaferIntentUtils.java index 854e142c7c2f..ec91da90729b 100644 --- a/services/core/java/com/android/server/pm/SaferIntentUtils.java +++ b/services/core/java/com/android/server/pm/SaferIntentUtils.java @@ -213,6 +213,7 @@ public class SaferIntentUtils { * CTS tests. The code in this method shall properly avoid control flows using these arguments. */ public static void blockNullAction(IntentArgs args, List componentList) { + if (args.intent.getAction() != null) return; if (ActivityManager.canAccessUnexportedComponents(args.callingUid)) return; final Computer computer = (Computer) args.snapshot; @@ -235,14 +236,11 @@ public class SaferIntentUtils { } final ParsedMainComponent comp = infoToComponent( resolveInfo.getComponentInfo(), resolver, args.isReceiver); - if (comp != null && !comp.getIntents().isEmpty() - && args.intent.getAction() == null) { + if (comp != null && !comp.getIntents().isEmpty()) { match = false; } } else if (c instanceof IntentFilter) { - if (args.intent.getAction() == null) { - match = false; - } + match = false; } if (!match) { diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java index 951986fbd71a..a09d4776d986 100644 --- a/services/core/java/com/android/server/pm/StorageEventHelper.java +++ b/services/core/java/com/android/server/pm/StorageEventHelper.java @@ -227,7 +227,7 @@ public final class StorageEventHelper extends StorageEventListener { } if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded); - mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm.snapshotComputer(), + mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm::snapshotComputer, true /* mediaStatus */, false /* replacing */, loaded); synchronized (mLoadedVolumes) { mLoadedVolumes.add(vol.getId()); @@ -279,7 +279,7 @@ public final class StorageEventHelper extends StorageEventListener { } if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); - mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm.snapshotComputer(), + mBroadcastHelper.sendResourcesChangedBroadcastAndNotify(mPm::snapshotComputer, false /* mediaStatus */, false /* replacing */, unloaded); synchronized (mLoadedVolumes) { mLoadedVolumes.remove(vol.getId()); diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java index 4e70cc52ef90..88fd1aa159d3 100644 --- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java +++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java @@ -192,21 +192,20 @@ public final class SuspendPackageHelper { } }); - final Computer newSnapshot = mPm.snapshotComputer(); if (!notifyPackagesList.isEmpty()) { final String[] changedPackages = notifyPackagesList.toArray(new String[0]); - mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot, + mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(mPm::snapshotComputer, suspended ? Intent.ACTION_PACKAGES_SUSPENDED : Intent.ACTION_PACKAGES_UNSUSPENDED, changedPackages, notifyUids.toArray(), quarantined, targetUserId); - mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, changedPackages, - suspended, targetUserId); + mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(mPm::snapshotComputer, + changedPackages, suspended, targetUserId); mPm.scheduleWritePackageRestrictions(targetUserId); } // Send the suspension changed broadcast to ensure suspension state is not stale. if (!changedPackagesList.isEmpty()) { - mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot, + mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(mPm::snapshotComputer, Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, changedPackagesList.toArray(new String[0]), changedUids.toArray(), quarantined, targetUserId); @@ -343,13 +342,12 @@ public final class SuspendPackageHelper { }); mPm.scheduleWritePackageRestrictions(targetUserId); - final Computer newSnapshot = mPm.snapshotComputer(); if (!unsuspendedPackages.isEmpty()) { final String[] packageArray = unsuspendedPackages.toArray( new String[unsuspendedPackages.size()]); - mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, packageArray, - false, targetUserId); - mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot, + mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(mPm::snapshotComputer, + packageArray, false, targetUserId); + mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(mPm::snapshotComputer, Intent.ACTION_PACKAGES_UNSUSPENDED, packageArray, unsuspendedUids.toArray(), false, targetUserId); } diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java index 041f2d3a459d..04ce4e692fef 100644 --- a/services/core/java/com/android/server/pm/UserDataPreparer.java +++ b/services/core/java/com/android/server/pm/UserDataPreparer.java @@ -68,6 +68,10 @@ class UserDataPreparer { void prepareUserData(UserInfo userInfo, int flags) { try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) { final StorageManager storage = mContext.getSystemService(StorageManager.class); + if (storage == null) { + Log.e(TAG, "prepareUserData failed due to unable get StorageManager"); + return; + } /* * Internal storage must be prepared before adoptable storage, since the user's volume * keys are stored in their internal storage. @@ -159,14 +163,16 @@ class UserDataPreparer { void destroyUserData(int userId, int flags) { try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) { final StorageManager storage = mContext.getSystemService(StorageManager.class); - /* - * Volume destruction order isn't really important, but to avoid any weird issues we - * process internal storage last, the opposite of prepareUserData. - */ - for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { - final String volumeUuid = vol.getFsUuid(); - if (volumeUuid != null) { - destroyUserDataLI(volumeUuid, userId, flags); + if (storage != null) { + /* + * Volume destruction order isn't really important, but to avoid any weird issues we + * process internal storage last, the opposite of prepareUserData. + */ + for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { + final String volumeUuid = vol.getFsUuid(); + if (volumeUuid != null) { + destroyUserDataLI(volumeUuid, userId, flags); + } } } destroyUserDataLI(null /* internal storage */, userId, flags); @@ -194,9 +200,10 @@ class UserDataPreparer { } } - // All the user's data directories should be empty now, so finish the job. - storage.destroyUserStorage(volumeUuid, userId, flags); - + if (storage != null) { + // All the user's data directories should be empty now, so finish the job. + storage.destroyUserStorage(volumeUuid, userId, flags); + } } catch (Exception e) { logCriticalInfo(Log.WARN, "Failed to destroy user " + userId + " on volume " + volumeUuid + ": " + e); diff --git a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java index e989d6875d15..e9cb279439a6 100644 --- a/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java +++ b/services/core/java/com/android/server/pm/permission/AccessCheckDelegate.java @@ -40,7 +40,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.TriFunction; import com.android.internal.util.function.UndecFunction; @@ -351,22 +351,22 @@ public interface AccessCheckDelegate extends CheckPermissionDelegate, CheckOpsDe @Override public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String featureId, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, - @Nullable String message, boolean shouldCollectMessage, int notedCount, - @NonNull NonaFunction<Integer, Integer, String, String, Integer, Boolean, String, - Boolean, Integer, SyncNotedAppOp> superImpl) { + @Nullable String message, boolean shouldCollectMessage, + @NonNull OctFunction<Integer, Integer, String, String, Integer, Boolean, String, + Boolean, SyncNotedAppOp> superImpl) { if (uid == mDelegateAndOwnerUid && isDelegateOp(code)) { final int shellUid = UserHandle.getUid(UserHandle.getUserId(uid), Process.SHELL_UID); final long identity = Binder.clearCallingIdentity(); try { return superImpl.apply(code, shellUid, SHELL_PKG, featureId, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); + shouldCollectAsyncNotedOp, message, shouldCollectMessage); } finally { Binder.restoreCallingIdentity(identity); } } return superImpl.apply(code, uid, packageName, featureId, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); + shouldCollectAsyncNotedOp, message, shouldCollectMessage); } @Override diff --git a/services/core/java/com/android/server/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java index 33210e28281e..ecffd382f542 100644 --- a/services/core/java/com/android/server/policy/AppOpsPolicy.java +++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java @@ -53,7 +53,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.function.DodecFunction; import com.android.internal.util.function.HexConsumer; import com.android.internal.util.function.HexFunction; -import com.android.internal.util.function.NonaFunction; +import com.android.internal.util.function.OctFunction; import com.android.internal.util.function.QuadFunction; import com.android.internal.util.function.UndecFunction; import com.android.server.LocalServices; @@ -246,12 +246,11 @@ public final class AppOpsPolicy implements AppOpsManagerInternal.CheckOpsDelegat public SyncNotedAppOp noteOperation(int code, int uid, @Nullable String packageName, @Nullable String attributionTag, int virtualDeviceId, boolean shouldCollectAsyncNotedOp, @Nullable String message, - boolean shouldCollectMessage, int notedCount, - @NonNull NonaFunction<Integer, Integer, String, String, - Integer, Boolean, String, Boolean, Integer, SyncNotedAppOp> superImpl) { + boolean shouldCollectMessage, @NonNull OctFunction<Integer, Integer, String, String, + Integer, Boolean, String, Boolean, SyncNotedAppOp> superImpl) { return superImpl.apply(resolveDatasourceOp(code, uid, packageName, attributionTag), resolveUid(code, uid), packageName, attributionTag, virtualDeviceId, - shouldCollectAsyncNotedOp, message, shouldCollectMessage, notedCount); + shouldCollectAsyncNotedOp, message, shouldCollectMessage); } @Override diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index f1a481155458..d5e4c3f1eb9f 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -88,10 +88,12 @@ import static com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGest import static com.android.hardware.input.Flags.inputManagerLifecycleSupport; import static com.android.hardware.input.Flags.keyboardA11yShortcutControl; import static com.android.hardware.input.Flags.modifierShortcutDump; +import static com.android.hardware.input.Flags.overridePowerKeyBehaviorInFocusedWindow; import static com.android.hardware.input.Flags.useKeyGestureEventHandler; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY; +import static com.android.server.GestureLauncherService.DOUBLE_POWER_TAP_COUNT_THRESHOLD; import static com.android.server.flags.Flags.modifierShortcutManagerMultiuser; import static com.android.server.flags.Flags.newBugreportKeyboardShortcut; -import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_KEYCHORD_DELAY; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED; @@ -432,6 +434,16 @@ public class PhoneWindowManager implements WindowManagerPolicy { "android.intent.action.VOICE_ASSIST_RETAIL"; /** + * Maximum amount of time in milliseconds between consecutive power onKeyDown events to be + * considered a multi-press, only used for the power button. + * Note: To maintain backwards compatibility for the power button, we are measuring the times + * between consecutive down events instead of the first tap's up event and the second tap's + * down event. + */ + @VisibleForTesting public static final int POWER_MULTI_PRESS_TIMEOUT_MILLIS = + ViewConfiguration.getMultiPressTimeout(); + + /** * Lock protecting internal state. Must not call out into window * manager with lock held. (This lock will be acquired in places * where the window manager is calling in with its own lock held.) @@ -492,6 +504,32 @@ public class PhoneWindowManager implements WindowManagerPolicy { private WindowWakeUpPolicy mWindowWakeUpPolicy; + /** + * The three variables below are used for custom power key gesture detection in + * PhoneWindowManager. They are used to detect when the power button has been double pressed + * and, when it does happen, makes the behavior overrideable by the app. + * + * We cannot use the {@link PowerKeyRule} for this because multi-press power gesture detection + * and behaviors are handled by {@link com.android.server.GestureLauncherService}, and the + * {@link PowerKeyRule} only handles single and long-presses of the power button. As a result, + * overriding the double tap behavior requires custom gesture detection here that mimics the + * logic in {@link com.android.server.GestureLauncherService}. + * + * Long-term, it would be beneficial to move all power gesture detection to + * {@link PowerKeyRule} so that this custom logic isn't required. + */ + // Time of last power down event. + private long mLastPowerDown; + + // Number of power button events consecutively triggered (within a specific timeout threshold). + private int mPowerButtonConsecutiveTaps = 0; + + // Whether a double tap of the power button has been detected. + volatile boolean mDoubleTapPowerDetected; + + // Runnable that is queued on a delay when the first power keyDown event is sent to the app. + private Runnable mPowerKeyDelayedRunnable = null; + boolean mSafeMode; // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. @@ -1097,6 +1135,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPowerKeyHandled = mPowerKeyHandled || hungUp || handledByPowerManager || isKeyGestureTriggered || mKeyCombinationManager.isPowerKeyIntercepted(); + + if (overridePowerKeyBehaviorInFocusedWindow()) { + mPowerKeyHandled |= mDoubleTapPowerDetected; + } + if (!mPowerKeyHandled) { if (!interactive) { wakeUpFromWakeKey(event); @@ -2669,7 +2712,19 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mShouldEarlyShortPressOnPower) { return; } - powerPress(downTime, 1 /*count*/, displayId); + // TODO(b/380433365): Remove deferring single power press action when refactoring. + if (overridePowerKeyBehaviorInFocusedWindow()) { + mDeferredKeyActionExecutor.cancelQueuedAction(KEYCODE_POWER); + mDeferredKeyActionExecutor.queueKeyAction( + KEYCODE_POWER, + downTime, + () -> { + powerPress(downTime, 1 /*count*/, displayId); + }); + } else { + powerPress(downTime, 1 /*count*/, displayId); + } + } @Override @@ -2700,7 +2755,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override void onMultiPress(long downTime, int count, int displayId) { - powerPress(downTime, count, displayId); + if (overridePowerKeyBehaviorInFocusedWindow()) { + mDeferredKeyActionExecutor.cancelQueuedAction(KEYCODE_POWER); + mDeferredKeyActionExecutor.queueKeyAction( + KEYCODE_POWER, + downTime, + () -> { + powerPress(downTime, count, displayId); + }); + } else { + powerPress(downTime, count, displayId); + } } @Override @@ -3477,6 +3542,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + if (overridePowerKeyBehaviorInFocusedWindow() && event.getKeyCode() == KEYCODE_POWER + && event.getAction() == KeyEvent.ACTION_UP + && mDoubleTapPowerDetected) { + mDoubleTapPowerDetected = false; + } + return needToConsumeKey ? keyConsumed : keyNotConsumed; } @@ -3992,6 +4063,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { sendSystemKeyToStatusBarAsync(event); return true; } + case KeyEvent.KEYCODE_POWER: + return interceptPowerKeyBeforeDispatching(focusedToken, event); case KeyEvent.KEYCODE_SCREENSHOT: if (firstDown) { interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/); @@ -4047,6 +4120,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { sendSystemKeyToStatusBarAsync(event); return true; } + case KeyEvent.KEYCODE_POWER: + return interceptPowerKeyBeforeDispatching(focusedToken, event); } if (isValidGlobalKey(keyCode) && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { @@ -4057,6 +4132,90 @@ public class PhoneWindowManager implements WindowManagerPolicy { return (metaState & KeyEvent.META_META_ON) != 0; } + /** + * Called by interceptKeyBeforeDispatching to handle interception logic for KEYCODE_POWER + * KeyEvents. + * + * @return true if intercepting the key, false if sending to app. + */ + private boolean interceptPowerKeyBeforeDispatching(IBinder focusedToken, KeyEvent event) { + if (!overridePowerKeyBehaviorInFocusedWindow()) { + //Flag disabled: intercept the power key and do not send to app. + return true; + } + if (event.getKeyCode() != KEYCODE_POWER) { + Log.wtf(TAG, "interceptPowerKeyBeforeDispatching received a non-power KeyEvent " + + "with key code: " + event.getKeyCode()); + return false; + } + + // Intercept keys (don't send to app) for 3x, 4x, 5x gestures) + if (mPowerButtonConsecutiveTaps > DOUBLE_POWER_TAP_COUNT_THRESHOLD) { + setDeferredKeyActionsExecutableAsync(KEYCODE_POWER, event.getDownTime()); + return true; + } + + // UP key; just reuse the original decision. + if (event.getAction() == KeyEvent.ACTION_UP) { + final Set<Integer> consumedKeys = mConsumedKeysForDevice.get(event.getDeviceId()); + return consumedKeys != null + && consumedKeys.contains(event.getKeyCode()); + } + + KeyInterceptionInfo info = + mWindowManagerInternal.getKeyInterceptionInfoFromToken(focusedToken); + + if (info == null || !mButtonOverridePermissionChecker.canWindowOverridePowerKey(mContext, + info.windowOwnerUid, info.inputFeaturesFlags)) { + // The focused window does not have the permission to override power key behavior. + if (DEBUG_INPUT) { + String interceptReason = ""; + if (info == null) { + interceptReason = "Window is null"; + } else if (!mButtonOverridePermissionChecker.canAppOverrideSystemKey(mContext, + info.windowOwnerUid)) { + interceptReason = "Application does not have " + + "OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW permission"; + } else { + interceptReason = "Window does not have inputFeatureFlag set"; + } + + Log.d(TAG, String.format("Intercepting KEYCODE_POWER event. action=%d, " + + "eventTime=%d to window=%s. interceptReason=%s. " + + "mDoubleTapPowerDetected=%b", + event.getAction(), event.getEventTime(), (info != null) + ? info.windowTitle : "null", interceptReason, + mDoubleTapPowerDetected)); + } + // Intercept the key (i.e. do not send to app) + setDeferredKeyActionsExecutableAsync(KEYCODE_POWER, event.getDownTime()); + return true; + } + + if (DEBUG_INPUT) { + Log.d(TAG, String.format("Sending KEYCODE_POWER to app. action=%d, " + + "eventTime=%d to window=%s. mDoubleTapPowerDetected=%b", + event.getAction(), event.getEventTime(), info.windowTitle, + mDoubleTapPowerDetected)); + } + + if (!mDoubleTapPowerDetected) { + //Single press: post a delayed runnable for the single press power action that will be + // called if it's not cancelled by a double press. + final var downTime = event.getDownTime(); + mPowerKeyDelayedRunnable = () -> + setDeferredKeyActionsExecutableAsync(KEYCODE_POWER, downTime); + mHandler.postDelayed(mPowerKeyDelayedRunnable, POWER_MULTI_PRESS_TIMEOUT_MILLIS); + } else if (mPowerKeyDelayedRunnable != null) { + //Double press detected: cancel the single press runnable. + mHandler.removeCallbacks(mPowerKeyDelayedRunnable); + mPowerKeyDelayedRunnable = null; + } + + // Focused window has permission. Send to app. + return false; + } + @SuppressLint("MissingPermission") private void initKeyGestures() { if (!useKeyGestureEventHandler()) { @@ -4633,6 +4792,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return true; } + if (overridePowerKeyBehaviorInFocusedWindow() && keyCode == KEYCODE_POWER) { + handleUnhandledSystemKey(event); + return true; + } + if (useKeyGestureEventHandler()) { return false; } @@ -5467,8 +5631,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { KeyEvent.actionToString(event.getAction()), mPowerKeyHandled ? 1 : 0, mSingleKeyGestureDetector.getKeyPressCounter(KeyEvent.KEYCODE_POWER)); - // Any activity on the power button stops the accessibility shortcut - result &= ~ACTION_PASS_TO_USER; + if (overridePowerKeyBehaviorInFocusedWindow()) { + result |= ACTION_PASS_TO_USER; + } else { + // Any activity on the power button stops the accessibility shortcut + result &= ~ACTION_PASS_TO_USER; + } + isWakeKey = false; // wake-up will be handled separately if (down) { interceptPowerKeyDown(event, interactiveAndAwake, isKeyGestureTriggered); @@ -5730,6 +5899,35 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (event.getKeyCode() == KEYCODE_POWER && event.getAction() == KeyEvent.ACTION_DOWN) { + if (overridePowerKeyBehaviorInFocusedWindow()) { + if (event.getRepeatCount() > 0) { + return; + } + if (mGestureLauncherService != null) { + mGestureLauncherService.processPowerKeyDown(event); + } + + if (detectDoubleTapPower(event)) { + mDoubleTapPowerDetected = true; + + // Copy of the event for handler in case the original event gets recycled. + KeyEvent eventCopy = KeyEvent.obtain(event); + mDeferredKeyActionExecutor.queueKeyAction( + KeyEvent.KEYCODE_POWER, + eventCopy.getEventTime(), + () -> { + if (!handleCameraGesture(eventCopy, interactive)) { + mSingleKeyGestureDetector.interceptKey( + eventCopy, interactive, defaultDisplayOn); + } else { + mSingleKeyGestureDetector.reset(); + } + eventCopy.recycle(); + }); + return; + } + } + mPowerKeyHandled = handleCameraGesture(event, interactive); if (mPowerKeyHandled) { // handled by camera gesture. @@ -5741,6 +5939,25 @@ public class PhoneWindowManager implements WindowManagerPolicy { mSingleKeyGestureDetector.interceptKey(event, interactive, defaultDisplayOn); } + private boolean detectDoubleTapPower(KeyEvent event) { + if (event.getKeyCode() != KEYCODE_POWER || event.getAction() != KeyEvent.ACTION_DOWN + || event.getRepeatCount() != 0) { + return false; + } + + final long powerTapInterval = event.getEventTime() - mLastPowerDown; + mLastPowerDown = event.getEventTime(); + if (powerTapInterval >= POWER_MULTI_PRESS_TIMEOUT_MILLIS) { + // Tap too slow for double press + mPowerButtonConsecutiveTaps = 1; + } else { + mPowerButtonConsecutiveTaps++; + } + + return powerTapInterval < POWER_MULTI_PRESS_TIMEOUT_MILLIS + && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD; + } + // The camera gesture will be detected by GestureLauncherService. private boolean handleCameraGesture(KeyEvent event, boolean interactive) { // camera gesture. @@ -7597,6 +7814,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { null) == PERMISSION_GRANTED; } + + boolean canWindowOverridePowerKey(Context context, int uid, int inputFeaturesFlags) { + return canAppOverrideSystemKey(context, uid) + && (inputFeaturesFlags & WindowManager.LayoutParams + .INPUT_FEATURE_RECEIVE_POWER_KEY_DOUBLE_PRESS) != 0; + } } private int getTargetDisplayIdForKeyEvent(KeyEvent event) { diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java index 8c588b4c9b98..63e8d9973237 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -195,22 +195,23 @@ public class BatteryUsageStatsProvider { mLastAccumulationMonotonicHistorySize = historySize; } - // No need to store the accumulated stats asynchronously, as the entire accumulation - // operation is async - handler.post(() -> accumulateBatteryUsageStats(stats, false)); + handler.post(() -> accumulateBatteryUsageStats(stats)); } /** * Computes BatteryUsageStats for the period since the last accumulated stats were stored, - * adds them to the accumulated stats and asynchronously saves the result. + * adds them to the accumulated stats and saves the result. */ public void accumulateBatteryUsageStats(BatteryStatsImpl stats) { - accumulateBatteryUsageStats(stats, true); - } - - private void accumulateBatteryUsageStats(BatteryStatsImpl stats, boolean storeAsync) { AccumulatedBatteryUsageStats accumulatedStats = loadAccumulatedBatteryUsageStats(); - updateAccumulatedBatteryUsageStats(accumulatedStats, stats); + + final BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder() + .setMaxStatsAgeMs(0) + .includeProcessStateData() + .includePowerStateData() + .includeScreenStateData() + .build(); + updateAccumulatedBatteryUsageStats(accumulatedStats, stats, query); PowerStatsSpan powerStatsSpan = new PowerStatsSpan(AccumulatedBatteryUsageStatsSection.ID); powerStatsSpan.addSection( @@ -219,13 +220,8 @@ public class BatteryUsageStatsProvider { accumulatedStats.startWallClockTime, accumulatedStats.endMonotonicTime - accumulatedStats.startMonotonicTime); mMonotonicClock.write(); - if (storeAsync) { - mPowerStatsStore.storePowerStatsSpanAsync(powerStatsSpan, - accumulatedStats.builder::discard); - } else { - mPowerStatsStore.storePowerStatsSpan(powerStatsSpan); - accumulatedStats.builder.discard(); - } + mPowerStatsStore.storePowerStatsSpanAsync(powerStatsSpan, + accumulatedStats.builder::discard); } /** @@ -273,7 +269,7 @@ public class BatteryUsageStatsProvider { BatteryUsageStats batteryUsageStats; if ((query.getFlags() & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_ACCUMULATED) != 0) { - batteryUsageStats = getAccumulatedBatteryUsageStats(stats, query); + batteryUsageStats = getAccumulatedBatteryUsageStats(stats, query, currentTimeMs); } else if (query.getAggregatedToTimestamp() == 0) { BatteryUsageStats.Builder builder = computeBatteryUsageStats(stats, query, query.getMonotonicStartTime(), @@ -292,13 +288,9 @@ public class BatteryUsageStatsProvider { } private BatteryUsageStats getAccumulatedBatteryUsageStats(BatteryStatsImpl stats, - BatteryUsageStatsQuery query) { + BatteryUsageStatsQuery query, long currentTimeMs) { AccumulatedBatteryUsageStats accumulatedStats = loadAccumulatedBatteryUsageStats(); - if (accumulatedStats.endMonotonicTime == MonotonicClock.UNDEFINED - || mMonotonicClock.monotonicTime() - accumulatedStats.endMonotonicTime - > query.getMaxStatsAge()) { - updateAccumulatedBatteryUsageStats(accumulatedStats, stats); - } + updateAccumulatedBatteryUsageStats(accumulatedStats, stats, query); return accumulatedStats.builder.build(); } @@ -329,7 +321,7 @@ public class BatteryUsageStatsProvider { } private void updateAccumulatedBatteryUsageStats(AccumulatedBatteryUsageStats accumulatedStats, - BatteryStatsImpl stats) { + BatteryStatsImpl stats, BatteryUsageStatsQuery query) { long startMonotonicTime = accumulatedStats.endMonotonicTime; if (startMonotonicTime == MonotonicClock.UNDEFINED) { startMonotonicTime = stats.getMonotonicStartTime(); @@ -341,7 +333,6 @@ public class BatteryUsageStatsProvider { accumulatedStats.builder = new BatteryUsageStats.Builder( stats.getCustomEnergyConsumerNames(), true, true, true, 0); accumulatedStats.startWallClockTime = stats.getStartClockTime(); - accumulatedStats.startMonotonicTime = stats.getMonotonicStartTime(); accumulatedStats.builder.setStatsStartTimestamp(accumulatedStats.startWallClockTime); } @@ -351,7 +342,7 @@ public class BatteryUsageStatsProvider { accumulatedStats.builder.setStatsDuration(endWallClockTime - startMonotonicTime); mPowerAttributor.estimatePowerConsumption(accumulatedStats.builder, stats.getHistory(), - startMonotonicTime, endMonotonicTime); + startMonotonicTime, MonotonicClock.UNDEFINED); populateGeneralInfo(accumulatedStats.builder, stats); } diff --git a/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java index 2609cf7aebfc..dcdd3bd8b3fa 100644 --- a/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java +++ b/services/core/java/com/android/server/power/stats/processor/PowerStatsAggregator.java @@ -23,7 +23,6 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BatteryStatsHistory; import com.android.internal.os.BatteryStatsHistoryIterator; -import com.android.internal.os.MonotonicClock; import java.util.function.Consumer; @@ -170,9 +169,6 @@ public class PowerStatsAggregator { } } } - if (endTimeMs != MonotonicClock.UNDEFINED) { - lastTime = endTimeMs; - } if (lastTime > baseTime) { mStats.setDuration(lastTime - baseTime); mStats.finish(lastTime); diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java index 24ed1bbe0eb1..57a0bb53c9dc 100644 --- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java +++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java @@ -18,6 +18,8 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static com.android.server.wm.SnapshotPersistQueue.MAX_STORE_QUEUE_DEPTH; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -343,6 +345,11 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#recordSnapshot " + activity); } + if (mPersister.mSnapshotPersistQueue.peekWriteQueueSize() >= MAX_STORE_QUEUE_DEPTH + || mPersister.mSnapshotPersistQueue.peekQueueSize() > MAX_PERSIST_SNAPSHOT_COUNT) { + Slog.w(TAG, "Skipping recording activity snapshot, too many requests!"); + return; + } final int size = activity.size(); final int[] mixedCode = new int[size]; if (size == 1) { @@ -432,7 +439,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord addBelowActivityIfExist(ar, mPendingLoadActivity, false, "load-snapshot"); } else { // remove the snapshot for the one below close - addBelowActivityIfExist(ar, mPendingRemoveActivity, true, "remove-snapshot"); + addBelowActivityIfExist(ar, mPendingRemoveActivity, false, "remove-snapshot"); } } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 90d3834b4543..2781592c6b4f 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -27,6 +27,7 @@ import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER; import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; +import static android.app.ActivityManager.isStartResultSuccessful; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; import static android.app.PendingIntent.FLAG_ONE_SHOT; @@ -891,7 +892,10 @@ class ActivityStarter { final ActivityOptions originalOptions = mRequest.activityOptions != null ? mRequest.activityOptions.getOriginalOptions() : null; // Only track the launch time of activity that will be resumed. - launchingRecord = mDoResume ? mLastStartActivityRecord : null; + if (mDoResume || (isStartResultSuccessful(res) + && mLastStartActivityRecord.getTask().isVisibleRequested())) { + launchingRecord = mLastStartActivityRecord; + } // If the new record is the one that started, a new activity has created. final boolean newActivityCreated = mStartActivity == launchingRecord; // Notify ActivityMetricsLogger that the activity has launched. diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 0b661580f450..c2141a7103be 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -260,6 +260,7 @@ import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.utils.RegionUtils; import com.android.server.wm.utils.RotationCache; import com.android.server.wm.utils.WmDisplayCutout; +import com.android.window.flags.Flags; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -1390,11 +1391,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mTokenMap.put(binder, token); if (token.asActivityRecord() == null) { - // Set displayContent for non-app token to prevent same token will add twice after - // onDisplayChanged. - // TODO: Check if it's fine that super.onDisplayChanged of WindowToken - // (WindowsContainer#onDisplayChanged) may skipped when token.mDisplayContent assigned. - token.mDisplayContent = this; + // Setting the mDisplayContent to the token is not needed: it is done by da.addChild + // below, that also calls onDisplayChanged once moved. + if (!Flags.reparentWindowTokenApi()) { + // Set displayContent for non-app token to prevent same token will add twice after + // onDisplayChanged. + // TODO: Check if it's fine that super.onDisplayChanged of WindowToken + // (WindowsContainer#onDisplayChanged) may skipped when token.mDisplayContent + // assigned. + token.mDisplayContent = this; + } // Add non-app token to container hierarchy on the display. App tokens are added through // the parent container managing them (e.g. Tasks). final DisplayArea.Tokens da = findAreaForToken(token).asTokens(); diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java index 8b63ecf7135f..a5454546341b 100644 --- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java +++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java @@ -50,7 +50,7 @@ import java.util.ArrayDeque; class SnapshotPersistQueue { private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotPersister" : TAG_WM; private static final long DELAY_MS = 100; - private static final int MAX_STORE_QUEUE_DEPTH = 2; + static final int MAX_STORE_QUEUE_DEPTH = 2; private static final int COMPRESS_QUALITY = 95; @GuardedBy("mLock") @@ -154,7 +154,12 @@ class SnapshotPersistQueue { } } - @VisibleForTesting + int peekWriteQueueSize() { + synchronized (mLock) { + return mStoreQueueItems.size(); + } + } + int peekQueueSize() { synchronized (mLock) { return mWriteQueue.size(); diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java index 809745e48300..6d0da1fd36f5 100644 --- a/services/core/java/com/android/server/wm/WindowContextListenerController.java +++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java @@ -167,6 +167,22 @@ class WindowContextListenerController { return true; } + boolean assertCallerCanReparentListener(@NonNull IBinder clientToken, + boolean callerCanManageAppTokens, int callingUid, int displayId) { + if (!assertCallerCanModifyListener(clientToken, callerCanManageAppTokens, callingUid)) { + return false; + } + + final WindowContainer<?> container = getContainer(clientToken); + if (container != null && container.getDisplayContent() != null + && container.getDisplayContent().mDisplayId == displayId) { + ProtoLog.i(WM_DEBUG_ADD_REMOVE, + "The listener has already been attached to the same display id"); + return false; + } + return true; + } + boolean hasListener(IBinder clientToken) { return mListeners.containsKey(clientToken); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b42ce64fa1d2..0b6ca75c5f0d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -358,6 +358,7 @@ import com.android.server.policy.WindowManagerPolicy.ScreenOffListener; import com.android.server.power.ShutdownThread; import com.android.server.utils.PriorityDump; import com.android.server.wallpaper.WallpaperCropper.WallpaperCropUtils; +import com.android.window.flags.Flags; import dalvik.annotation.optimization.NeverCompile; @@ -3042,6 +3043,81 @@ public class WindowManagerService extends IWindowManager.Stub } } + @Override + public boolean reparentWindowContextToDisplayArea( + @NonNull IApplicationThread appThread, @NonNull IBinder clientToken, int displayId) { + if (!Flags.reparentWindowTokenApi()) { + return false; + } + Objects.requireNonNull(appThread); + Objects.requireNonNull(clientToken); + final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS, + "reparentWindowContextToDisplayArea", false /* printLog */); + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + final WindowProcessController wpc = mAtmService.getProcessController(appThread); + if (wpc == null) { + ProtoLog.w(WM_ERROR, "reparentWindowContextToDisplayArea: calling from" + + " non-existing process pid=%d uid=%d", callingPid, callingUid); + return false; + } + final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId); + if (dc == null) { + ProtoLog.w(WM_ERROR, "reparentWindowContextToDisplayArea: trying to attach" + + " to a non-existing display:%d", displayId); + return false; + } + + if (!mWindowContextListenerController.assertCallerCanReparentListener(clientToken, + callerCanManageAppTokens, callingUid, displayId)) { + return false; + } + final WindowContainer<?> container = mWindowContextListenerController.getContainer( + clientToken); + + final WindowToken token = container != null ? container.asWindowToken() : null; + if (token != null && token.isFromClient()) { + ProtoLog.d(WM_DEBUG_ADD_REMOVE, "Reparenting from dc to displayId=%d", + displayId); + // Reparent the window created for this window context. + dc.reParentWindowToken(token); + hideUntilNextDraw(token); + // This makes sure there is a traversal scheduled that will eventually report + // the window resize to the client. + dc.setLayoutNeeded(); + requestTraversal(); + return true; + } + + final int type = mWindowContextListenerController.getWindowType(clientToken); + final Bundle options = mWindowContextListenerController.getOptions(clientToken); + // No window yet, switch listening DA. + final DisplayArea<?> da = dc.findAreaForWindowType(type, options, + callerCanManageAppTokens, false /* roundedCornerOverlay */); + mWindowContextListenerController.registerWindowContainerListener(wpc, clientToken, + da, type, options, true /* shouldDispatchConfigWhenRegistering */); + return true; + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + private void hideUntilNextDraw(@NonNull WindowToken token) { + final WindowState topChild = token.getTopChild(); + if (topChild != null) { + mTransactionFactory.get().hide(token.mSurfaceControl).apply(); + topChild.applyWithNextDraw(t -> { + if (token.mSurfaceControl != null) { + t.show(token.mSurfaceControl); + } + }); + } + } + /** Returns {@code true} if this binder is a registered window token. */ @Override public boolean isWindowToken(IBinder binder) { @@ -9020,16 +9096,19 @@ public class WindowManagerService extends IWindowManager.Stub clearPointerDownOutsideFocusRunnable(); + final InputTarget focusedInputTarget = mFocusedInputTarget; if (shouldDelayTouchOutside(t)) { - mPointerDownOutsideFocusRunnable = () -> handlePointerDownOutsideFocus(t); + mPointerDownOutsideFocusRunnable = + () -> handlePointerDownOutsideFocus(t, focusedInputTarget); mH.postDelayed(mPointerDownOutsideFocusRunnable, POINTER_DOWN_OUTSIDE_FOCUS_TIMEOUT_MS); } else if (!fromHandler) { // Still post the runnable to handler thread in case there is already a runnable // in execution, but still waiting to hold the wm lock. - mPointerDownOutsideFocusRunnable = () -> handlePointerDownOutsideFocus(t); + mPointerDownOutsideFocusRunnable = + () -> handlePointerDownOutsideFocus(t, focusedInputTarget); mH.post(mPointerDownOutsideFocusRunnable); } else { - handlePointerDownOutsideFocus(t); + handlePointerDownOutsideFocus(t, focusedInputTarget); } } @@ -9061,8 +9140,15 @@ public class WindowManagerService extends IWindowManager.Stub return shouldDelayTouchForEmbeddedActivity || shouldDelayTouchForFreeform; } - private void handlePointerDownOutsideFocus(InputTarget t) { + private void handlePointerDownOutsideFocus(InputTarget t, InputTarget focusedInputTarget) { synchronized (mGlobalLock) { + if (mFocusedInputTarget != focusedInputTarget) { + // Skip if the mFocusedInputTarget is already changed. This is possible if the + // pointer-down-outside-focus event is delayed to be handled. + ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, + "Skip onPointerDownOutsideFocusLocked due to input target changed %s", t); + return; + } if (mPointerDownOutsideFocusRunnable != null && mH.hasCallbacks(mPointerDownOutsideFocusRunnable)) { // Skip if there's another pending pointer-down-outside-focus event. diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index cebe790bb1b9..447d443282bd 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5750,9 +5750,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP || mKeyInterceptionInfo.layoutParamsPrivateFlags != getAttrs().privateFlags || mKeyInterceptionInfo.layoutParamsType != getAttrs().type || mKeyInterceptionInfo.windowTitle != getWindowTag() - || mKeyInterceptionInfo.windowOwnerUid != getOwningUid()) { + || mKeyInterceptionInfo.windowOwnerUid != getOwningUid() + || mKeyInterceptionInfo.inputFeaturesFlags != getAttrs().inputFeatures) { mKeyInterceptionInfo = new KeyInterceptionInfo(getAttrs().type, getAttrs().privateFlags, - getWindowTag().toString(), getOwningUid()); + getWindowTag().toString(), getOwningUid(), getAttrs().inputFeatures); } return mKeyInterceptionInfo; } diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 832295a7e031..cca73c574951 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -49,6 +49,7 @@ import android.window.WindowContext; import com.android.internal.protolog.ProtoLog; import com.android.server.policy.WindowManagerPolicy; +import com.android.window.flags.Flags; import java.io.PrintWriter; import java.util.ArrayList; @@ -386,7 +387,15 @@ class WindowToken extends WindowContainer<WindowState> { @Override void onDisplayChanged(DisplayContent dc) { - dc.reParentWindowToken(this); + if (!Flags.reparentWindowTokenApi()) { + dc.reParentWindowToken(this); + } else { + // This check is needed to break recursion, as DisplayContent#reparentWindowToken also + // triggers a WindowToken#onDisplayChanged. + if (dc.getWindowToken(token) == null) { + dc.reParentWindowToken(this); + } + } // TODO(b/36740756): One day this should perhaps be hooked // up with goodToGo, so we don't move a window diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 65315af45486..92dbf63b3cf7 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -2933,7 +2933,7 @@ public final class SystemServer implements Dumpable { t.traceEnd(); // UprobeStats DynamicInstrumentationManager - if (com.android.art.flags.Flags.executableMethodFileOffsets()) { + if (android.uprobestats.flags.Flags.executableMethodFileOffsets()) { t.traceBegin("StartDynamicInstrumentationManager"); mSystemServiceManager.startService(DynamicInstrumentationManagerService.class); t.traceEnd(); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt index de029e0d770f..90e1263b76ec 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/DistractingPackageHelperTest.kt @@ -56,8 +56,8 @@ class DistractingPackageHelperTest : PackageHelperTestBase() { testHandler.flush() verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) - verify(broadcastHelper).sendDistractingPackagesChanged(any(Computer::class.java), - pkgListCaptor.capture(), any(), any(), flagsCaptor.capture()) + verify(broadcastHelper).sendDistractingPackagesChanged( + any(), pkgListCaptor.capture(), any(), any(), flagsCaptor.capture()) val modifiedPackages = pkgListCaptor.value val distractionFlags = flagsCaptor.value @@ -158,8 +158,7 @@ class DistractingPackageHelperTest : PackageHelperTestBase() { verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) verify(broadcastHelper).sendDistractingPackagesChanged( - any(Computer::class.java), pkgListCaptor.capture(), any(), eq(TEST_USER_ID), - flagsCaptor.capture()) + any(), pkgListCaptor.capture(), any(), eq(TEST_USER_ID), flagsCaptor.capture()) val modifiedPackages = pkgListCaptor.value val distractionFlags = flagsCaptor.value assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2) @@ -198,12 +197,12 @@ class DistractingPackageHelperTest : PackageHelperTestBase() { @Test fun sendDistractingPackagesChanged() { - broadcastHelper.sendDistractingPackagesChanged(pms.snapshotComputer(), + broadcastHelper.sendDistractingPackagesChanged(pms::snapshotComputer, packagesToChange, uidsToChange, TEST_USER_ID, PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) testHandler.flush() - verify(broadcastHelper).sendDistractingPackagesChanged(any(Computer::class.java), - pkgListCaptor.capture(), uidsCaptor.capture(), eq(TEST_USER_ID), any()) + verify(broadcastHelper).sendDistractingPackagesChanged( + any(), pkgListCaptor.capture(), uidsCaptor.capture(), eq(TEST_USER_ID), any()) var changedPackages = pkgListCaptor.value var changedUids = uidsCaptor.value diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt index 7444403f88c8..60e82501db1c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt @@ -58,8 +58,8 @@ class SuspendPackageHelperTest : PackageHelperTestBase() { testHandler.flush() verify(pms).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) - verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser(any(Computer::class.java), - eq(Intent.ACTION_PACKAGES_SUSPENDED), pkgListCaptor.capture(), any(), any(), any()) + verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser(any(), + eq(Intent.ACTION_PACKAGES_SUSPENDED), pkgListCaptor.capture(), any(), any(), any()) var modifiedPackages = pkgListCaptor.value assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2) @@ -149,11 +149,11 @@ class SuspendPackageHelperTest : PackageHelperTestBase() { testHandler.flush() verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) - verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser(any(Computer::class.java), - eq(Intent.ACTION_PACKAGES_UNSUSPENDED), pkgListCaptor.capture(), any(), any(), - any()) - verify(broadcastHelper).sendMyPackageSuspendedOrUnsuspended(any(Computer::class.java), - any(), any(), any()) + verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser( + any(), eq(Intent.ACTION_PACKAGES_UNSUSPENDED), + pkgListCaptor.capture(), any(), any(), any()) + verify(broadcastHelper).sendMyPackageSuspendedOrUnsuspended( + any(), any(), any(), any()) var modifiedPackages = pkgListCaptor.value assertThat(modifiedPackages).asList().containsExactly(TEST_PACKAGE_1, TEST_PACKAGE_2) @@ -230,10 +230,10 @@ class SuspendPackageHelperTest : PackageHelperTestBase() { testHandler.flush() verify(pms, times(2)).scheduleWritePackageRestrictions(eq(TEST_USER_ID)) - verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser(any(Computer::class.java), - eq(Intent.ACTION_PACKAGES_UNSUSPENDED), any(), any(), any(), any()) - verify(broadcastHelper).sendMyPackageSuspendedOrUnsuspended(any(Computer::class.java), - any(), any(), any()) + verify(broadcastHelper).sendPackagesSuspendedOrUnsuspendedForUser( + any(), eq(Intent.ACTION_PACKAGES_UNSUSPENDED), any(), any(), any(), any()) + verify(broadcastHelper).sendMyPackageSuspendedOrUnsuspended( + any(), any(), any(), any()) assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(), TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull() diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java index 73dcfe77e67f..709f83ba907d 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java @@ -36,7 +36,6 @@ import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.ConditionVariable; -import android.os.Handler; import android.os.Parcel; import android.os.Process; import android.os.UidBatteryConsumer; @@ -82,9 +81,8 @@ public class BatteryUsageStatsProviderTest { .setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 4000.0); private MockClock mMockClock = mStatsRule.getMockClock(); - private MonotonicClock mMonotonicClock = mStatsRule.getMonotonicClock(); + private MonotonicClock mMonotonicClock = new MonotonicClock(666777, mMockClock); private Context mContext; - private PowerStatsStore mPowerStatsStore; @Before public void setup() throws IOException { @@ -95,9 +93,6 @@ public class BatteryUsageStatsProviderTest { } else { mContext = InstrumentationRegistry.getContext(); } - mPowerStatsStore = spy(new PowerStatsStore( - new File(mStatsRule.getHistoryDir(), getClass().getSimpleName()), - mStatsRule.getHandler())); } @Test @@ -279,7 +274,10 @@ public class BatteryUsageStatsProviderTest { powerAttributor.setPowerComponentSupported(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, true); - BatteryUsageStatsProvider provider = createBatteryUsageStatsProvider(0); + BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext, + powerAttributor, mStatsRule.getPowerProfile(), + mStatsRule.getCpuScalingPolicies(), mock(PowerStatsStore.class), 0, mMockClock, + mMonotonicClock); return provider.getBatteryUsageStats(batteryStats, BatteryUsageStatsQuery.DEFAULT); } @@ -333,30 +331,30 @@ public class BatteryUsageStatsProviderTest { BatteryStats.HistoryItem item; assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_RESET, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 1_000_000); assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 1_000_000); assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isNotEqualTo(0); assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_NONE, null, 0, 3_600_000, 90, 2_000_000); assertThat(item.states & BatteryStats.HistoryItem.STATE_CPU_RUNNING_FLAG).isEqualTo(0); assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_START, "foo", APP_UID, 3_600_000, 90, 3_000_000); assertThat(item = iterator.next()).isNotNull(); - assertHistoryItem(batteryStats, item, + assertHistoryItem(item, BatteryStats.HistoryItem.CMD_UPDATE, BatteryStats.HistoryItem.EVENT_ALARM | BatteryStats.HistoryItem.EVENT_FLAG_FINISH, "foo", APP_UID, 3_600_000, 90, 3_001_000); @@ -443,15 +441,14 @@ public class BatteryUsageStatsProviderTest { assertThat(item.eventTag.string).startsWith(uid + " "); assertThat(item.batteryChargeUah).isEqualTo(3_600_000); assertThat(item.batteryLevel).isEqualTo(90); - assertThat(item.time).isEqualTo(batteryStats.getMonotonicStartTime() + 1_000_000); + assertThat(item.time).isEqualTo((long) 1_000_000); } assertThat(expectedUid).isEqualTo(200); } - private void assertHistoryItem(MockBatteryStatsImpl batteryStats, BatteryStats.HistoryItem item, - int command, int eventCode, String tag, int uid, int batteryChargeUah, int batteryLevel, - long elapsedTimeMs) { + private void assertHistoryItem(BatteryStats.HistoryItem item, int command, int eventCode, + String tag, int uid, int batteryChargeUah, int batteryLevel, long elapsedTimeMs) { assertThat(item.cmd).isEqualTo(command); assertThat(item.eventCode).isEqualTo(eventCode); if (tag == null) { @@ -463,7 +460,7 @@ public class BatteryUsageStatsProviderTest { assertThat(item.batteryChargeUah).isEqualTo(batteryChargeUah); assertThat(item.batteryLevel).isEqualTo(batteryLevel); - assertThat(item.time).isEqualTo(batteryStats.getMonotonicStartTime() + elapsedTimeMs); + assertThat(item.time).isEqualTo(elapsedTimeMs); } @Test @@ -569,66 +566,38 @@ public class BatteryUsageStatsProviderTest { assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); assertThat(stats.getStatsEndTimestamp()).isEqualTo(55 * MINUTE_IN_MS); - assertBatteryConsumer(stats, 180.0, (10 + 20) * MINUTE_IN_MS); - assertBatteryConsumer(stats, APP_UID, 180.0, (10 + 20) * MINUTE_IN_MS); + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) + .isWithin(0.0001) + .of(180.0); // 360 mA * 0.5 hours + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) + .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) + .isEqualTo((10 + 20) * MINUTE_IN_MS); + final UidBatteryConsumer uidBatteryConsumer = stats.getUidBatteryConsumers().stream() + .filter(uid -> uid.getUid() == APP_UID).findFirst().get(); + assertThat(uidBatteryConsumer + .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) + .isWithin(0.1) + .of(180.0); stats.close(); } @Test public void accumulateBatteryUsageStats() throws Throwable { - MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); - accumulateBatteryUsageStats(batteryStats, 10000000, 0); + accumulateBatteryUsageStats(10000000, 1); // Accumulate every 200 bytes of battery history - accumulateBatteryUsageStats(batteryStats, 200, 2); - accumulateBatteryUsageStats(batteryStats, 50, 4); + accumulateBatteryUsageStats(200, 2); + accumulateBatteryUsageStats(50, 5); // Accumulate on every invocation of accumulateBatteryUsageStats - accumulateBatteryUsageStats(batteryStats, 0, 7); + accumulateBatteryUsageStats(0, 7); } - @Test - public void getAccumulatedBatteryUsageStats() throws Throwable { - MockBatteryStatsImpl batteryStats = mStatsRule.getBatteryStats(); - - // Only accumulate the first 25 minutes - accumulateBatteryUsageStats(batteryStats, 200, 1); - - BatteryUsageStatsProvider batteryUsageStatsProvider = createBatteryUsageStatsProvider(200); - - // At this point the last stored accumulated stats are `115 - 30 = 85` minutes old - BatteryUsageStats stats = batteryUsageStatsProvider.getBatteryUsageStats(batteryStats, - new BatteryUsageStatsQuery.Builder() - .accumulated() - .setMaxStatsAgeMs(90 * MINUTE_IN_MS) - .build()); - - assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); - assertThat(stats.getStatsEndTimestamp()).isEqualTo(30 * MINUTE_IN_MS); - assertBatteryConsumer(stats, 60.0, 10 * MINUTE_IN_MS); - assertBatteryConsumer(stats, APP_UID, 60.0, 10 * MINUTE_IN_MS); - - stats.close(); - - // Now force the usage stats to catch up to the current time - stats = batteryUsageStatsProvider.getBatteryUsageStats(batteryStats, - new BatteryUsageStatsQuery.Builder() - .accumulated() - .setMaxStatsAgeMs(5 * MINUTE_IN_MS) - .build()); - - assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); - assertThat(stats.getStatsEndTimestamp()).isEqualTo(115 * MINUTE_IN_MS); - assertBatteryConsumer(stats, 360.0, 60 * MINUTE_IN_MS); - assertBatteryConsumer(stats, APP_UID, 360.0, 60 * MINUTE_IN_MS); - - stats.close(); - } - - private void accumulateBatteryUsageStats(MockBatteryStatsImpl batteryStatsImpl, - int accumulatedBatteryUsageStatsSpanSize, int expectedNumberOfUpdates) - throws Throwable { - Handler handler = mStatsRule.getHandler(); - MockBatteryStatsImpl batteryStats = spy(batteryStatsImpl); + private void accumulateBatteryUsageStats(int accumulatedBatteryUsageStatsSpanSize, + int expectedNumberOfUpdates) throws Throwable { + BatteryStatsImpl batteryStats = spy(mStatsRule.getBatteryStats()); // Note - these two are in microseconds when(batteryStats.computeBatteryTimeRemaining(anyLong())).thenReturn(111_000L); when(batteryStats.computeChargeTimeRemaining(anyLong())).thenReturn(777_000L); @@ -641,76 +610,82 @@ public class BatteryUsageStatsProviderTest { batteryStats.resetAllStatsAndHistoryLocked(BatteryStatsImpl.RESET_REASON_ADB_COMMAND); } - mPowerStatsStore.reset(); + PowerStatsStore powerStatsStore = spy(new PowerStatsStore( + new File(mStatsRule.getHistoryDir(), getClass().getSimpleName()), + mStatsRule.getHandler())); + powerStatsStore.reset(); int[] count = new int[1]; doAnswer(inv -> { count[0]++; - return inv.callRealMethod(); - }).when(mPowerStatsStore).storePowerStatsSpan(any(PowerStatsSpan.class)); + return null; + }).when(powerStatsStore).storePowerStatsSpan(any(PowerStatsSpan.class)); - BatteryUsageStatsProvider batteryUsageStatsProvider = createBatteryUsageStatsProvider( - accumulatedBatteryUsageStatsSpanSize); + MultiStatePowerAttributor powerAttributor = new MultiStatePowerAttributor(mContext, + powerStatsStore, mStatsRule.getPowerProfile(), mStatsRule.getCpuScalingPolicies(), + () -> 3500); + for (int powerComponentId = 0; powerComponentId < BatteryConsumer.POWER_COMPONENT_COUNT; + powerComponentId++) { + powerAttributor.setPowerComponentSupported(powerComponentId, true); + } + powerAttributor.setPowerComponentSupported(BatteryConsumer.POWER_COMPONENT_ANY, true); + + BatteryUsageStatsProvider provider = new BatteryUsageStatsProvider(mContext, + powerAttributor, mStatsRule.getPowerProfile(), + mStatsRule.getCpuScalingPolicies(), powerStatsStore, + accumulatedBatteryUsageStatsSpanSize, mMockClock, mMonotonicClock); - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - setTime(10 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOnLocked(APP_UID, 10 * MINUTE_IN_MS, 10 * MINUTE_IN_MS); } - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - setTime(20 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOffLocked(APP_UID, 20 * MINUTE_IN_MS, 20 * MINUTE_IN_MS); } - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - setTime(30 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOnLocked(APP_UID, 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS); } - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - // Make sure the accumulated stats are computed and saved before generating more history - mStatsRule.waitForBackgroundThread(); - - setTime(50 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOffLocked(APP_UID, 50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS); } setTime(55 * MINUTE_IN_MS); - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); // This section has not been saved yet, but should be added to the accumulated totals - setTime(80 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOnLocked(APP_UID, 80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS); } - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + provider.accumulateBatteryUsageStatsAsync(batteryStats, mStatsRule.getHandler()); - setTime(110 * MINUTE_IN_MS); synchronized (batteryStats) { batteryStats.noteFlashlightOffLocked(APP_UID, 110 * MINUTE_IN_MS, 110 * MINUTE_IN_MS); } setTime(115 * MINUTE_IN_MS); - batteryUsageStatsProvider.accumulateBatteryUsageStatsAsync(batteryStats, handler); + // Pick up the remainder of battery history that has not yet been accumulated + provider.accumulateBatteryUsageStats(batteryStats); mStatsRule.waitForBackgroundThread(); - BatteryUsageStats stats = batteryUsageStatsProvider.getBatteryUsageStats(batteryStats, + BatteryUsageStats stats = provider.getBatteryUsageStats(batteryStats, new BatteryUsageStatsQuery.Builder().accumulated().build()); assertThat(stats.getStatsStartTimestamp()).isEqualTo(5 * MINUTE_IN_MS); @@ -721,55 +696,29 @@ public class BatteryUsageStatsProviderTest { assertThat(stats.getBatteryCapacity()).isEqualTo(4000); // from PowerProfile // Total: 10 + 20 + 30 = 60 - assertBatteryConsumer(stats, 360.0, 60 * MINUTE_IN_MS); - assertBatteryConsumer(stats, APP_UID, 360.0, 60 * MINUTE_IN_MS); - stats.close(); - - mStatsRule.waitForBackgroundThread(); - - assertThat(count[0]).isEqualTo(expectedNumberOfUpdates); - } - - private BatteryUsageStatsProvider createBatteryUsageStatsProvider( - int accumulatedBatteryUsageStatsSpanSize) { - MultiStatePowerAttributor powerAttributor = new MultiStatePowerAttributor(mContext, - mPowerStatsStore, mStatsRule.getPowerProfile(), mStatsRule.getCpuScalingPolicies(), - () -> 3500); - for (int powerComponentId = 0; powerComponentId < BatteryConsumer.POWER_COMPONENT_COUNT; - powerComponentId++) { - powerAttributor.setPowerComponentSupported(powerComponentId, true); - } - powerAttributor.setPowerComponentSupported(BatteryConsumer.POWER_COMPONENT_ANY, true); - - return new BatteryUsageStatsProvider(mContext, powerAttributor, - mStatsRule.getPowerProfile(), mStatsRule.getCpuScalingPolicies(), mPowerStatsStore, - accumulatedBatteryUsageStatsSpanSize, mMockClock, mMonotonicClock); - } - - private static void assertBatteryConsumer(BatteryUsageStats stats, double expectedPowerMah, - long expectedDurationMs) { - AggregateBatteryConsumer aggregatedConsumer = stats.getAggregateBatteryConsumer( - BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE); - assertThat(aggregatedConsumer + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) .isWithin(0.0001) - .of(expectedPowerMah); - assertThat(aggregatedConsumer + .of(360.0); // 360 mA * 1.0 hour + assertThat(stats.getAggregateBatteryConsumer( + BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) - .isEqualTo(expectedDurationMs); - } + .isEqualTo(60 * MINUTE_IN_MS); - private static void assertBatteryConsumer(BatteryUsageStats stats, int uid, - double expectedPowerMah, long expectedDurationMs) { final UidBatteryConsumer uidBatteryConsumer = stats.getUidBatteryConsumers().stream() - .filter(u -> u.getUid() == uid).findFirst().get(); + .filter(uid -> uid.getUid() == APP_UID).findFirst().get(); assertThat(uidBatteryConsumer .getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) .isWithin(0.1) - .of(expectedPowerMah); + .of(360.0); assertThat(uidBatteryConsumer .getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) - .isEqualTo(expectedDurationMs); + .isEqualTo(60 * MINUTE_IN_MS); + + assertThat(count[0]).isEqualTo(expectedNumberOfUpdates); + + stats.close(); } private void setTime(long timeMs) { diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java index 9e7e0b646047..a3c7ece386c7 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java @@ -41,7 +41,6 @@ import android.util.SparseArray; import android.util.Xml; import com.android.internal.os.CpuScalingPolicies; -import com.android.internal.os.MonotonicClock; import com.android.internal.os.PowerProfile; import com.android.internal.power.EnergyConsumerStats; @@ -66,7 +65,6 @@ public class BatteryUsageStatsRule implements TestRule { private final PowerProfile mPowerProfile; private final MockClock mMockClock = new MockClock(); - private final MonotonicClock mMonotonicClock = new MonotonicClock(666777, mMockClock); private String mTestName; private boolean mCreateTempDirectory; private File mHistoryDir; @@ -120,7 +118,7 @@ public class BatteryUsageStatsRule implements TestRule { clearDirectory(); } mBatteryStats = new MockBatteryStatsImpl(mBatteryStatsConfigBuilder.build(), - mMockClock, mMonotonicClock, mHistoryDir, mHandler, new PowerStatsUidResolver()); + mMockClock, mHistoryDir, mHandler, new PowerStatsUidResolver()); mBatteryStats.setPowerProfile(mPowerProfile); mBatteryStats.setCpuScalingPolicies(new CpuScalingPolicies(mCpusByPolicy, mFreqsByPolicy)); synchronized (mBatteryStats) { @@ -146,10 +144,6 @@ public class BatteryUsageStatsRule implements TestRule { return mMockClock; } - public MonotonicClock getMonotonicClock() { - return mMonotonicClock; - } - public Handler getHandler() { return mHandler; } diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java index 9a38209a7d17..b374a3202fa2 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java @@ -77,15 +77,9 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { new PowerStatsUidResolver()); } - MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, - File historyDirectory, Handler handler, PowerStatsUidResolver powerStatsUidResolver) { - this(config, clock, new MonotonicClock(0, clock), historyDirectory, handler, - powerStatsUidResolver); - } - - MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, MonotonicClock monotonicClock, - File historyDirectory, Handler handler, PowerStatsUidResolver powerStatsUidResolver) { - super(config, clock, monotonicClock, historyDirectory, handler, + MockBatteryStatsImpl(BatteryStatsConfig config, Clock clock, File historyDirectory, + Handler handler, PowerStatsUidResolver powerStatsUidResolver) { + super(config, clock, new MonotonicClock(0, clock), historyDirectory, handler, mock(PlatformIdleStateCallback.class), mock(EnergyStatsRetriever.class), mock(UserInfoProvider.class), mockPowerProfile(), new CpuScalingPolicies(new SparseArray<>(), new SparseArray<>()), diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java index d243f92a139f..38fe6134d992 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/processor/PowerStatsExporterTest.java @@ -408,7 +408,7 @@ public class PowerStatsExporterTest { BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder( new String[]{"cu570m"}, /* includeProcessStateData */ true, true, true, /* powerThreshold */ 0); - exportAggregatedPowerStats(builder, 3700, 7500); + exportAggregatedPowerStats(builder, 3700, 6700); BatteryUsageStats actual = builder.build(); String message = "Actual BatteryUsageStats: " + actual; diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java index 8024915692aa..9850cb09ae2b 100644 --- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java @@ -16,7 +16,12 @@ package com.android.server; -import static com.android.server.GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS; +import static android.service.quickaccesswallet.Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP; +import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap; + +import static com.android.server.GestureLauncherService.LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER; +import static com.android.server.GestureLauncherService.LAUNCH_WALLET_ON_DOUBLE_TAP_POWER; +import static com.android.server.GestureLauncherService.POWER_DOUBLE_TAP_MAX_TIME_MS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -24,19 +29,27 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.PendingIntent; import android.app.StatusBarManager; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Resources; import android.os.Looper; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; +import android.service.quickaccesswallet.QuickAccessWalletClient; import android.telecom.TelecomManager; import android.test.mock.MockContentResolver; import android.testing.TestableLooper; @@ -55,6 +68,7 @@ import com.android.server.statusbar.StatusBarManagerInternal; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -62,6 +76,8 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * Unit tests for {@link GestureLauncherService}. @@ -90,9 +106,32 @@ public class GestureLauncherServiceTest { private @Mock TelecomManager mTelecomManager; private @Mock MetricsLogger mMetricsLogger; @Mock private UiEventLogger mUiEventLogger; + @Mock private QuickAccessWalletClient mQuickAccessWalletClient; private MockContentResolver mContentResolver; private GestureLauncherService mGestureLauncherService; + private Context mInstrumentationContext = + InstrumentationRegistry.getInstrumentation().getContext(); + + private static final String LAUNCH_TEST_WALLET_ACTION = "LAUNCH_TEST_WALLET_ACTION"; + private static final String LAUNCH_FALLBACK_ACTION = "LAUNCH_FALLBACK_ACTION"; + private PendingIntent mGesturePendingIntent = + PendingIntent.getBroadcast( + mInstrumentationContext, + 0, + new Intent(LAUNCH_TEST_WALLET_ACTION), + PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT); + + private PendingIntent mFallbackPendingIntent = + PendingIntent.getBroadcast( + mInstrumentationContext, + 0, + new Intent(LAUNCH_FALLBACK_ACTION), + PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT); + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @BeforeClass public static void oneTimeInitialization() { if (Looper.myLooper() == null) { @@ -115,9 +154,49 @@ public class GestureLauncherServiceTest { when(mContext.getContentResolver()).thenReturn(mContentResolver); when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager); when(mTelecomManager.createLaunchEmergencyDialerIntent(null)).thenReturn(new Intent()); + when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true); + + mGestureLauncherService = + new GestureLauncherService( + mContext, mMetricsLogger, mQuickAccessWalletClient, mUiEventLogger); + + withDoubleTapPowerGestureEnableSettingValue(true); + withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER); + } - mGestureLauncherService = new GestureLauncherService(mContext, mMetricsLogger, - mUiEventLogger); + private WalletLaunchedReceiver registerWalletLaunchedReceiver(String action) { + IntentFilter filter = new IntentFilter(action); + WalletLaunchedReceiver receiver = new WalletLaunchedReceiver(); + mInstrumentationContext.registerReceiver(receiver, filter, Context.RECEIVER_EXPORTED); + return receiver; + } + + /** + * A simple {@link BroadcastReceiver} implementation that counts down a {@link CountDownLatch} + * when a matching message is received + */ + private static final class WalletLaunchedReceiver extends BroadcastReceiver { + private static final int TIMEOUT_SECONDS = 3; + + private final CountDownLatch mLatch; + + WalletLaunchedReceiver() { + mLatch = new CountDownLatch(1); + } + + @Override + public void onReceive(Context context, Intent intent) { + mLatch.countDown(); + context.unregisterReceiver(this); + } + + Boolean waitUntilShown() { + try { + return mLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + return false; + } + } } @Test @@ -134,37 +213,123 @@ public class GestureLauncherServiceTest { @Test public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingDisabled() { - withCameraDoubleTapPowerEnableConfigValue(false); - withCameraDoubleTapPowerDisableSettingValue(1); + if (launchWalletOptionOnPowerDoubleTap()) { + withDoubleTapPowerEnabledConfigValue(false); + withDoubleTapPowerGestureEnableSettingValue(false); + withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER); + } else { + withCameraDoubleTapPowerEnableConfigValue(false); + withCameraDoubleTapPowerDisableSettingValue(1); + } assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled( mContext, FAKE_USER_ID)); } @Test public void testIsCameraDoubleTapPowerSettingEnabled_configFalseSettingEnabled() { - withCameraDoubleTapPowerEnableConfigValue(false); - withCameraDoubleTapPowerDisableSettingValue(0); - assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled( - mContext, FAKE_USER_ID)); + if (launchWalletOptionOnPowerDoubleTap()) { + withDoubleTapPowerEnabledConfigValue(false); + withDoubleTapPowerGestureEnableSettingValue(true); + withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER); + assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled( + mContext, FAKE_USER_ID)); + } else { + withCameraDoubleTapPowerEnableConfigValue(false); + withCameraDoubleTapPowerDisableSettingValue(0); + assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled( + mContext, FAKE_USER_ID)); + } } @Test public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingDisabled() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(1); + if (launchWalletOptionOnPowerDoubleTap()) { + withDoubleTapPowerEnabledConfigValue(true); + withDoubleTapPowerGestureEnableSettingValue(false); + withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER); + } else { + withCameraDoubleTapPowerEnableConfigValue(true); + withCameraDoubleTapPowerDisableSettingValue(1); + } assertFalse(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled( mContext, FAKE_USER_ID)); } @Test public void testIsCameraDoubleTapPowerSettingEnabled_configTrueSettingEnabled() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); + if (launchWalletOptionOnPowerDoubleTap()) { + withDoubleTapPowerEnabledConfigValue(true); + withDoubleTapPowerGestureEnableSettingValue(true); + withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER); + } else { + withCameraDoubleTapPowerEnableConfigValue(true); + withCameraDoubleTapPowerDisableSettingValue(0); + } assertTrue(mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled( mContext, FAKE_USER_ID)); } @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testIsCameraDoubleTapPowerSettingEnabled_actionWallet() { + withDoubleTapPowerEnabledConfigValue(true); + withDoubleTapPowerGestureEnableSettingValue(true); + withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER); + + assertFalse( + mGestureLauncherService.isCameraDoubleTapPowerSettingEnabled( + mContext, FAKE_USER_ID)); + } + + @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testIsWalletDoubleTapPowerSettingEnabled() { + withDoubleTapPowerEnabledConfigValue(true); + withDoubleTapPowerGestureEnableSettingValue(true); + withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER); + + assertTrue( + mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled( + mContext, FAKE_USER_ID)); + } + + @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testIsWalletDoubleTapPowerSettingEnabled_configDisabled() { + withDoubleTapPowerEnabledConfigValue(false); + withDoubleTapPowerGestureEnableSettingValue(true); + withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER); + + assertTrue( + mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled( + mContext, FAKE_USER_ID)); + } + + @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testIsWalletDoubleTapPowerSettingEnabled_settingDisabled() { + withDoubleTapPowerEnabledConfigValue(true); + withDoubleTapPowerGestureEnableSettingValue(false); + withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER); + + assertFalse( + mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled( + mContext, FAKE_USER_ID)); + } + + @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testIsWalletDoubleTapPowerSettingEnabled_actionCamera() { + withDoubleTapPowerEnabledConfigValue(true); + withDoubleTapPowerGestureEnableSettingValue(true); + withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER); + + assertFalse( + mGestureLauncherService.isWalletDoubleTapPowerSettingEnabled( + mContext, FAKE_USER_ID)); + } + + @Test public void testIsEmergencyGestureSettingEnabled_settingDisabled() { withEmergencyGestureEnabledConfigValue(true); withEmergencyGestureEnabledSettingValue(false); @@ -245,12 +410,9 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); + enableCameraGesture(); - long eventTime = INITIAL_EVENT_TIME_MILLIS + - CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + long eventTime = INITIAL_EVENT_TIME_MILLIS + POWER_DOUBLE_TAP_MAX_TIME_MS - 1; KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); boolean interactive = true; @@ -284,8 +446,12 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffInteractive() { - withCameraDoubleTapPowerEnableConfigValue(false); - withCameraDoubleTapPowerDisableSettingValue(1); + if (launchWalletOptionOnPowerDoubleTap()) { + withDoubleTapPowerGestureEnableSettingValue(false); + } else { + withCameraDoubleTapPowerEnableConfigValue(false); + withCameraDoubleTapPowerDisableSettingValue(1); + } mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); long eventTime = INITIAL_EVENT_TIME_MILLIS; @@ -298,7 +464,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -329,8 +495,12 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOffInteractive() { - withCameraDoubleTapPowerEnableConfigValue(false); - withCameraDoubleTapPowerDisableSettingValue(1); + if (launchWalletOptionOnPowerDoubleTap()) { + withDoubleTapPowerGestureEnableSettingValue(false); + } else { + withCameraDoubleTapPowerEnableConfigValue(false); + withCameraDoubleTapPowerDisableSettingValue(1); + } mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); long eventTime = INITIAL_EVENT_TIME_MILLIS; @@ -343,7 +513,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -422,10 +592,7 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupComplete() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); - withUserSetupCompleteValue(true); + enableCameraGesture(); long eventTime = INITIAL_EVENT_TIME_MILLIS; KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, @@ -437,7 +604,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -470,15 +637,145 @@ public class GestureLauncherServiceTest { } @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void + testInterceptPowerKeyDown_fiveInboundPresses_walletAndEmergencyEnabled_bothLaunch() { + WalletLaunchedReceiver receiver = registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION); + setUpGetGestureTargetActivityPendingIntent(mGesturePendingIntent); + enableEmergencyGesture(); + enableWalletGesture(); + + // First event + long eventTime = INITIAL_EVENT_TIME_MILLIS; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true); + + assertTrue(receiver.waitUntilShown()); + + // Presses 3 and 4 should not trigger any gesture + for (int i = 0; i < 2; i++) { + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, false); + } + + // Fifth button press should trigger the emergency flow + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true); + + verify(mUiEventLogger, times(1)) + .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER); + verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected(); + } + + @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testInterceptPowerKeyDown_intervalInBoundsWalletPowerGesture() { + WalletLaunchedReceiver receiver = registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION); + setUpGetGestureTargetActivityPendingIntent(mGesturePendingIntent); + enableWalletGesture(); + enableEmergencyGesture(); + + long eventTime = INITIAL_EVENT_TIME_MILLIS; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true); + assertTrue(receiver.waitUntilShown()); + } + + @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testInterceptPowerKeyDown_walletGestureOn_quickAccessWalletServiceUnavailable() { + when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false); + WalletLaunchedReceiver receiver = registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION); + setUpGetGestureTargetActivityPendingIntent(mGesturePendingIntent); + enableWalletGesture(); + + // First event + long eventTime = INITIAL_EVENT_TIME_MILLIS; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, false); + + assertFalse(receiver.waitUntilShown()); + } + + @Test + public void testInterceptPowerKeyDown_walletGestureOn_userSetupIncomplete() { + WalletLaunchedReceiver receiver = registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION); + setUpGetGestureTargetActivityPendingIntent(mGesturePendingIntent); + enableWalletGesture(); + withUserSetupCompleteValue(false); + + // First event + long eventTime = INITIAL_EVENT_TIME_MILLIS; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + + assertFalse(receiver.waitUntilShown()); + } + + @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testInterceptPowerKeyDown_walletPowerGesture_nullPendingIntent() { + WalletLaunchedReceiver gestureReceiver = + registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION); + setUpGetGestureTargetActivityPendingIntent(null); + WalletLaunchedReceiver fallbackReceiver = + registerWalletLaunchedReceiver(LAUNCH_FALLBACK_ACTION); + setUpWalletFallbackPendingIntent(mFallbackPendingIntent); + enableWalletGesture(); + enableEmergencyGesture(); + + // First event + long eventTime = INITIAL_EVENT_TIME_MILLIS; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true); + + assertFalse(gestureReceiver.waitUntilShown()); + assertTrue(fallbackReceiver.waitUntilShown()); + } + + @Test + @RequiresFlagsEnabled(FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testInterceptPowerKeyDown_walletPowerGesture_intervalOutOfBounds() { + WalletLaunchedReceiver gestureReceiver = + registerWalletLaunchedReceiver(LAUNCH_TEST_WALLET_ACTION); + setUpGetGestureTargetActivityPendingIntent(null); + WalletLaunchedReceiver fallbackReceiver = + registerWalletLaunchedReceiver(LAUNCH_FALLBACK_ACTION); + setUpWalletFallbackPendingIntent(mFallbackPendingIntent); + enableWalletGesture(); + enableEmergencyGesture(); + + // First event + long eventTime = INITIAL_EVENT_TIME_MILLIS; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS; + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + + assertFalse(gestureReceiver.waitUntilShown()); + assertFalse(fallbackReceiver.waitUntilShown()); + } + + @Test public void testInterceptPowerKeyDown_fiveInboundPresses_cameraAndEmergencyEnabled_bothLaunch() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - withEmergencyGestureEnabledConfigValue(true); - withEmergencyGestureEnabledSettingValue(true); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); - mGestureLauncherService.updateEmergencyGestureEnabled(); - withUserSetupCompleteValue(true); + enableCameraGesture(); + enableEmergencyGesture(); // First button press does nothing long eventTime = INITIAL_EVENT_TIME_MILLIS; @@ -491,7 +788,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; // 2nd button triggers camera eventTime += interval; @@ -580,7 +877,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; // 3 more button presses which should not trigger any gesture (camera gesture disabled) for (int i = 0; i < 3; i++) { eventTime += interval; @@ -634,7 +931,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; // 3 more button presses which should not trigger any gesture, but intercepts action. for (int i = 0; i < 3; i++) { eventTime += interval; @@ -737,7 +1034,7 @@ public class GestureLauncherServiceTest { interactive, outLaunched); assertTrue(intercepted); assertFalse(outLaunched.value); - interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; } } @@ -765,7 +1062,7 @@ public class GestureLauncherServiceTest { interactive, outLaunched); assertTrue(intercepted); assertFalse(outLaunched.value); - interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; } } @@ -916,7 +1213,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE, @@ -947,9 +1244,7 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); + enableCameraGesture(); withUserSetupCompleteValue(false); long eventTime = INITIAL_EVENT_TIME_MILLIS; @@ -962,7 +1257,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -995,9 +1290,7 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalMidBoundsCameraPowerGestureOnInteractive() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); + enableCameraGesture(); long eventTime = INITIAL_EVENT_TIME_MILLIS; KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, @@ -1009,7 +1302,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -1042,9 +1335,7 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnInteractive() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); + enableCameraGesture(); long eventTime = INITIAL_EVENT_TIME_MILLIS; KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, @@ -1087,8 +1378,12 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOffNotInteractive() { - withCameraDoubleTapPowerEnableConfigValue(false); - withCameraDoubleTapPowerDisableSettingValue(1); + if (launchWalletOptionOnPowerDoubleTap()) { + withDoubleTapPowerGestureEnableSettingValue(false); + } else { + withCameraDoubleTapPowerEnableConfigValue(false); + withCameraDoubleTapPowerDisableSettingValue(1); + } mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); long eventTime = INITIAL_EVENT_TIME_MILLIS; @@ -1101,7 +1396,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -1146,7 +1441,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -1223,10 +1518,7 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupComplete() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); - withUserSetupCompleteValue(true); + enableCameraGesture(); long eventTime = INITIAL_EVENT_TIME_MILLIS; KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, @@ -1238,7 +1530,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -1272,9 +1564,7 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnNotInteractiveSetupIncomplete() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); + enableCameraGesture(); withUserSetupCompleteValue(false); long eventTime = INITIAL_EVENT_TIME_MILLIS; @@ -1287,7 +1577,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -1332,7 +1622,7 @@ public class GestureLauncherServiceTest { assertFalse(intercepted); assertFalse(outLaunched.value); - final long interval = CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS; + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS; eventTime += interval; keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); @@ -1365,9 +1655,7 @@ public class GestureLauncherServiceTest { @Test public void testInterceptPowerKeyDown_intervalOutOfBoundsCameraPowerGestureOnNotInteractive() { - withCameraDoubleTapPowerEnableConfigValue(true); - withCameraDoubleTapPowerDisableSettingValue(0); - mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); + enableCameraGesture(); long eventTime = INITIAL_EVENT_TIME_MILLIS; KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, @@ -1409,12 +1697,53 @@ public class GestureLauncherServiceTest { } /** + * If processPowerKeyDown is called instead of interceptPowerKeyDown (meaning the double tap + * gesture isn't performed), the emergency gesture is still launched. + */ + @Test + public void + testProcessPowerKeyDown_fiveInboundPresses_cameraDoesNotLaunch_emergencyGestureLaunches() { + enableCameraGesture(); + enableEmergencyGesture(); + + // First event + long eventTime = INITIAL_EVENT_TIME_MILLIS; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, false, false); + + //Second event; call processPowerKeyDown without calling interceptPowerKeyDown + final long interval = POWER_DOUBLE_TAP_MAX_TIME_MS - 1; + eventTime += interval; + KeyEvent keyEvent = + new KeyEvent( + IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); + mGestureLauncherService.processPowerKeyDown(keyEvent); + + verify(mMetricsLogger, never()) + .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt()); + verify(mUiEventLogger, never()).log(any()); + + // Presses 3 and 4 should not trigger any gesture + for (int i = 0; i < 2; i++) { + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, false); + } + + // Fifth button press should still trigger the emergency flow + eventTime += interval; + sendPowerKeyDownToGestureLauncherServiceAndAssertValues(eventTime, true, true); + + verify(mUiEventLogger, times(1)) + .log(GestureLauncherService.GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER); + verify(mStatusBarManagerInternal).onEmergencyActionLaunchGestureDetected(); + } + + /** * Helper method to trigger emergency gesture by pressing button for 5 times. * * @return last event time. */ private long triggerEmergencyGesture() { - return triggerEmergencyGesture(CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1); + return triggerEmergencyGesture(POWER_DOUBLE_TAP_MAX_TIME_MS - 1); } /** @@ -1473,6 +1802,27 @@ public class GestureLauncherServiceTest { .thenReturn(enableConfigValue); } + private void withDoubleTapPowerEnabledConfigValue(boolean enable) { + when(mResources.getBoolean(com.android.internal.R.bool.config_doubleTapPowerGestureEnabled)) + .thenReturn(enable); + } + + private void withDoubleTapPowerGestureEnableSettingValue(boolean enable) { + Settings.Secure.putIntForUser( + mContentResolver, + Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, + enable ? 1 : 0, + UserHandle.USER_CURRENT); + } + + private void withDefaultDoubleTapPowerGestureAction(int action) { + Settings.Secure.putIntForUser( + mContentResolver, + Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE, + action, + UserHandle.USER_CURRENT); + } + private void withEmergencyGestureEnabledConfigValue(boolean enableConfigValue) { when(mResources.getBoolean( com.android.internal.R.bool.config_emergencyGestureEnabled)) @@ -1510,4 +1860,72 @@ public class GestureLauncherServiceTest { userSetupCompleteValue, UserHandle.USER_CURRENT); } + + private void setUpGetGestureTargetActivityPendingIntent(PendingIntent pendingIntent) { + doAnswer( + invocation -> { + QuickAccessWalletClient.GesturePendingIntentCallback callback = + (QuickAccessWalletClient.GesturePendingIntentCallback) + invocation.getArguments()[1]; + callback.onGesturePendingIntentRetrieved(pendingIntent); + return null; + }) + .when(mQuickAccessWalletClient) + .getGestureTargetActivityPendingIntent(any(), any()); + } + + private void setUpWalletFallbackPendingIntent(PendingIntent pendingIntent) { + doAnswer( + invocation -> { + QuickAccessWalletClient.WalletPendingIntentCallback callback = + (QuickAccessWalletClient.WalletPendingIntentCallback) + invocation.getArguments()[1]; + callback.onWalletPendingIntentRetrieved(pendingIntent); + return null; + }) + .when(mQuickAccessWalletClient) + .getWalletPendingIntent(any(), any()); + } + + private void enableWalletGesture() { + withDefaultDoubleTapPowerGestureAction(LAUNCH_WALLET_ON_DOUBLE_TAP_POWER); + withDoubleTapPowerGestureEnableSettingValue(true); + withDoubleTapPowerEnabledConfigValue(true); + + mGestureLauncherService.updateWalletDoubleTapPowerEnabled(); + withUserSetupCompleteValue(true); + } + + private void enableEmergencyGesture() { + withEmergencyGestureEnabledConfigValue(true); + withEmergencyGestureEnabledSettingValue(true); + mGestureLauncherService.updateEmergencyGestureEnabled(); + withUserSetupCompleteValue(true); + } + + private void enableCameraGesture() { + if (launchWalletOptionOnPowerDoubleTap()) { + withDoubleTapPowerEnabledConfigValue(true); + withDoubleTapPowerGestureEnableSettingValue(true); + withDefaultDoubleTapPowerGestureAction(LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER); + } else { + withCameraDoubleTapPowerEnableConfigValue(true); + withCameraDoubleTapPowerDisableSettingValue(0); + } + mGestureLauncherService.updateCameraDoubleTapPowerEnabled(); + withUserSetupCompleteValue(true); + } + + private void sendPowerKeyDownToGestureLauncherServiceAndAssertValues( + long eventTime, boolean expectedIntercept, boolean expectedOutLaunchedValue) { + KeyEvent keyEvent = + new KeyEvent( + IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE, IGNORED_REPEAT); + boolean interactive = true; + MutableBoolean outLaunched = new MutableBoolean(true); + boolean intercepted = + mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive, outLaunched); + assertEquals(intercepted, expectedIntercept); + assertEquals(outLaunched.value, expectedOutLaunchedValue); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java index 5127b2d11e44..c6df146dd42a 100644 --- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java @@ -22,6 +22,8 @@ import static com.android.compatibility.common.util.PollingCheck.waitFor; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -921,6 +923,41 @@ public final class DeviceStateManagerServiceTest { }); } + @Test + public void shouldShowRdmEduDialog1() { + // RDM V1 Cases + assertTrue(DeviceStateManagerService.shouldShowRdmEduDialog( + false /* hasControlDeviceStatePermission */, + false /* requestingRdmOuterDefault */, + false /* isDeviceClosed (no-op) */)); + + assertFalse(DeviceStateManagerService.shouldShowRdmEduDialog( + true /* hasControlDeviceStatePermission */, + false /* requestingRdmOuterDefault */, + true /* isDeviceClosed (no-op) */)); + + // RDM V2 Cases + // hasControlDeviceStatePermission = false + assertFalse(DeviceStateManagerService.shouldShowRdmEduDialog( + false /* hasControlDeviceStatePermission */, + true /* requestingRdmOuterDefault */, + false /* isDeviceClosed */)); + assertTrue(DeviceStateManagerService.shouldShowRdmEduDialog( + false /* hasControlDeviceStatePermission */, + true /* requestingRdmOuterDefault */, + true /* isDeviceClosed */)); + + // hasControlDeviceStatePermission = true + assertFalse(DeviceStateManagerService.shouldShowRdmEduDialog( + true /* hasControlDeviceStatePermission */, + true /* requestingRdmOuterDefault */, + false /* isDeviceClosed */)); + assertFalse(DeviceStateManagerService.shouldShowRdmEduDialog( + true /* hasControlDeviceStatePermission */, + true /* requestingRdmOuterDefault */, + true /* isDeviceClosed */)); + } + /** * Common code to verify the handling of FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP flag. * diff --git a/services/tests/wmtests/res/xml/bookmarks.xml b/services/tests/wmtests/res/xml/bookmarks.xml index 787f4e85c012..3fc7c7692abc 100644 --- a/services/tests/wmtests/res/xml/bookmarks.xml +++ b/services/tests/wmtests/res/xml/bookmarks.xml @@ -22,7 +22,7 @@ androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CONTACTS" - androidprv:keycode="KEYCODE_C" + androidprv:keycode="KEYCODE_P" androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_EMAIL" @@ -30,21 +30,13 @@ androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALENDAR" - androidprv:keycode="KEYCODE_K" + androidprv:keycode="KEYCODE_C" androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MAPS" androidprv:keycode="KEYCODE_M" androidprv:modifierState="META" /> <bookmark - category="android.intent.category.APP_MUSIC" - androidprv:keycode="KEYCODE_P" - androidprv:modifierState="META" /> - <bookmark - role="android.app.role.SMS" - androidprv:keycode="KEYCODE_S" - androidprv:modifierState="META" /> - <bookmark category="android.intent.category.APP_CALCULATOR" androidprv:keycode="KEYCODE_U" androidprv:modifierState="META" /> 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 32ba8f5f64d1..41865b209f01 100644 --- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java @@ -258,9 +258,9 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { {"EXPLORER key -> Launch Default Browser", new int[]{KeyEvent.KEYCODE_EXPLORER}, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_BROWSER, KeyEvent.KEYCODE_EXPLORER, 0}, - {"Meta + C -> Launch Default Contacts", new int[]{META_KEY, KeyEvent.KEYCODE_C}, + {"Meta + P -> Launch Default Contacts", new int[]{META_KEY, KeyEvent.KEYCODE_P}, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS, - KeyEvent.KEYCODE_C, META_ON}, + KeyEvent.KEYCODE_P, META_ON}, {"CONTACTS key -> Launch Default Contacts", new int[]{KeyEvent.KEYCODE_CONTACTS}, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CONTACTS, KeyEvent.KEYCODE_CONTACTS, 0}, @@ -270,15 +270,12 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { {"ENVELOPE key -> Launch Default Email", new int[]{KeyEvent.KEYCODE_ENVELOPE}, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_EMAIL, KeyEvent.KEYCODE_ENVELOPE, 0}, - {"Meta + K -> Launch Default Calendar", new int[]{META_KEY, KeyEvent.KEYCODE_K}, + {"Meta + C -> Launch Default Calendar", new int[]{META_KEY, KeyEvent.KEYCODE_C}, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR, - KeyEvent.KEYCODE_K, META_ON}, + KeyEvent.KEYCODE_C, META_ON}, {"CALENDAR key -> Launch Default Calendar", new int[]{KeyEvent.KEYCODE_CALENDAR}, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_CALENDAR, KeyEvent.KEYCODE_CALENDAR, 0}, - {"Meta + P -> Launch Default Music", new int[]{META_KEY, KeyEvent.KEYCODE_P}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC, - KeyEvent.KEYCODE_P, META_ON}, {"MUSIC key -> Launch Default Music", new int[]{KeyEvent.KEYCODE_MUSIC}, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MUSIC, KeyEvent.KEYCODE_MUSIC, 0}, @@ -291,11 +288,7 @@ public class KeyGestureEventTests extends ShortcutKeyTestBase { KeyEvent.KEYCODE_CALCULATOR, 0}, {"Meta + M -> Launch Default Maps", new int[]{META_KEY, KeyEvent.KEYCODE_M}, KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MAPS, - KeyEvent.KEYCODE_M, META_ON}, - {"Meta + S -> Launch Default Messaging App", - new int[]{META_KEY, KeyEvent.KEYCODE_S}, - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_DEFAULT_MESSAGING, - KeyEvent.KEYCODE_S, META_ON}}; + KeyEvent.KEYCODE_M, META_ON}}; } @Keep diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java index cf5323e1f3a5..35b077e30f12 100644 --- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutTests.java @@ -26,7 +26,6 @@ import static android.view.KeyEvent.KEYCODE_E; import static android.view.KeyEvent.KEYCODE_ENTER; import static android.view.KeyEvent.KEYCODE_H; import static android.view.KeyEvent.KEYCODE_J; -import static android.view.KeyEvent.KEYCODE_K; import static android.view.KeyEvent.KEYCODE_M; import static android.view.KeyEvent.KEYCODE_META_LEFT; import static android.view.KeyEvent.KEYCODE_N; @@ -67,14 +66,12 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { // These shortcuts should align with those defined in // services/tests/wmtests/res/xml/bookmarks.xml INTENT_SHORTCUTS.append(KEYCODE_U, Intent.CATEGORY_APP_CALCULATOR); - INTENT_SHORTCUTS.append(KEYCODE_C, Intent.CATEGORY_APP_CONTACTS); + INTENT_SHORTCUTS.append(KEYCODE_P, Intent.CATEGORY_APP_CONTACTS); INTENT_SHORTCUTS.append(KEYCODE_E, Intent.CATEGORY_APP_EMAIL); - INTENT_SHORTCUTS.append(KEYCODE_K, Intent.CATEGORY_APP_CALENDAR); + INTENT_SHORTCUTS.append(KEYCODE_C, Intent.CATEGORY_APP_CALENDAR); INTENT_SHORTCUTS.append(KEYCODE_M, Intent.CATEGORY_APP_MAPS); - INTENT_SHORTCUTS.append(KEYCODE_P, Intent.CATEGORY_APP_MUSIC); ROLE_SHORTCUTS.append(KEYCODE_B, RoleManager.ROLE_BROWSER); - ROLE_SHORTCUTS.append(KEYCODE_S, RoleManager.ROLE_SMS); } private static final int ANY_DISPLAY_ID = 123; @@ -109,7 +106,7 @@ public class ModifierShortcutTests extends ShortcutKeyTestBase { sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_B}, 0); mPhoneWindowManager.assertLaunchRole(RoleManager.ROLE_BROWSER); - sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_C}, 0); + sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_P}, 0); mPhoneWindowManager.assertLaunchCategory(Intent.CATEGORY_APP_CONTACTS); sendKeyCombination(new int[]{KEYCODE_META_LEFT, KEYCODE_SHIFT_LEFT, KEYCODE_J}, 0); diff --git a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java index 05a1482b9be6..1cc4db91b1d3 100644 --- a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java @@ -18,15 +18,22 @@ package com.android.server.policy; import static android.view.KeyEvent.KEYCODE_POWER; import static android.view.KeyEvent.KEYCODE_VOLUME_UP; +import static com.android.hardware.input.Flags.FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_ASSISTANT; import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GLOBAL_ACTIONS; +import static com.android.server.policy.PhoneWindowManager.POWER_MULTI_PRESS_TIMEOUT_MILLIS; import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_POWER_DREAM_OR_SLEEP; import static com.android.server.policy.PhoneWindowManager.SHORT_PRESS_POWER_GO_TO_SLEEP; +import static org.junit.Assert.assertEquals; + +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.view.Display; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; /** @@ -39,8 +46,12 @@ public class PowerKeyGestureTests extends ShortcutKeyTestBase { @Before public void setUp() { setUpPhoneWindowManager(); + mPhoneWindowManager.overrideStatusBarManagerInternal(); } + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + /** * Power single press to turn screen on/off. */ @@ -50,6 +61,8 @@ public class PowerKeyGestureTests extends ShortcutKeyTestBase { sendKey(KEYCODE_POWER); mPhoneWindowManager.assertPowerSleep(); + mPhoneWindowManager.moveTimeForward(POWER_MULTI_PRESS_TIMEOUT_MILLIS); + // turn screen on when begin from non-interactive. mPhoneWindowManager.overrideDisplayState(Display.STATE_OFF); sendKey(KEYCODE_POWER); @@ -90,7 +103,7 @@ public class PowerKeyGestureTests extends ShortcutKeyTestBase { mPhoneWindowManager.overrideCanStartDreaming(false); sendKey(KEYCODE_POWER); sendKey(KEYCODE_POWER); - mPhoneWindowManager.assertCameraLaunch(); + mPhoneWindowManager.assertDoublePowerLaunch(); mPhoneWindowManager.assertDidNotLockAfterAppTransitionFinished(); } @@ -101,7 +114,7 @@ public class PowerKeyGestureTests extends ShortcutKeyTestBase { public void testPowerDoublePress() { sendKey(KEYCODE_POWER); sendKey(KEYCODE_POWER); - mPhoneWindowManager.assertCameraLaunch(); + mPhoneWindowManager.assertDoublePowerLaunch(); } /** @@ -111,12 +124,14 @@ public class PowerKeyGestureTests extends ShortcutKeyTestBase { public void testPowerLongPress() { // Show assistant. mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_ASSISTANT); - sendKey(KEYCODE_POWER, true); + sendKey(KEYCODE_POWER, SingleKeyGestureDetector.sDefaultLongPressTimeout); mPhoneWindowManager.assertSearchManagerLaunchAssist(); + mPhoneWindowManager.moveTimeForward(POWER_MULTI_PRESS_TIMEOUT_MILLIS); + // Show global actions. mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_GLOBAL_ACTIONS); - sendKey(KEYCODE_POWER, true); + sendKey(KEYCODE_POWER, SingleKeyGestureDetector.sDefaultLongPressTimeout); mPhoneWindowManager.assertShowGlobalActionsCalled(); } @@ -141,4 +156,139 @@ public class PowerKeyGestureTests extends ShortcutKeyTestBase { sendKey(KEYCODE_POWER); mPhoneWindowManager.assertNoPowerSleep(); } + + /** + * Double press of power when the window handles the power key events. The + * system double power gesture launch should not be performed. + */ + @Test + @EnableFlags(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public void testPowerDoublePress_windowHasOverridePermissionAndKeysHandled() { + mPhoneWindowManager.overrideCanWindowOverridePowerKey(true); + setDispatchedKeyHandler(keyEvent -> true); + + sendKey(KEYCODE_POWER); + sendKey(KEYCODE_POWER); + + mPhoneWindowManager.assertDidNotLockAfterAppTransitionFinished(); + + mPhoneWindowManager.assertNoDoublePowerLaunch(); + } + + /** + * Double press of power when the window doesn't handle the power key events. + * The system default gesture launch should be performed and the app should receive both events. + */ + @Test + @EnableFlags(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public void testPowerDoublePress_windowHasOverridePermissionAndKeysUnHandled() { + mPhoneWindowManager.overrideCanWindowOverridePowerKey(true); + setDispatchedKeyHandler(keyEvent -> false); + + sendKey(KEYCODE_POWER); + sendKey(KEYCODE_POWER); + + mPhoneWindowManager.assertDidNotLockAfterAppTransitionFinished(); + mPhoneWindowManager.assertDoublePowerLaunch(); + assertEquals(getDownKeysDispatched(), 2); + assertEquals(getUpKeysDispatched(), 2); + } + + /** + * Triple press of power when the window handles the power key double press gesture. + * The system default gesture launch should not be performed, and the app only receives the + * first two presses. + */ + @Test + @EnableFlags(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public void testPowerTriplePress_windowHasOverridePermissionAndKeysHandled() { + mPhoneWindowManager.overrideCanWindowOverridePowerKey(true); + setDispatchedKeyHandler(keyEvent -> true); + + sendKey(KEYCODE_POWER); + sendKey(KEYCODE_POWER); + sendKey(KEYCODE_POWER); + + mPhoneWindowManager.assertDidNotLockAfterAppTransitionFinished(); + mPhoneWindowManager.assertNoDoublePowerLaunch(); + assertEquals(getDownKeysDispatched(), 2); + assertEquals(getUpKeysDispatched(), 2); + } + + /** + * Tests a single press, followed by a double press when the window can handle the power key. + * The app should receive all 3 events. + */ + @Test + @EnableFlags(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public void testPowerTriplePressWithDelay_windowHasOverridePermissionAndKeysHandled() { + mPhoneWindowManager.overrideCanWindowOverridePowerKey(true); + setDispatchedKeyHandler(keyEvent -> true); + + sendKey(KEYCODE_POWER); + mPhoneWindowManager.moveTimeForward(POWER_MULTI_PRESS_TIMEOUT_MILLIS); + sendKey(KEYCODE_POWER); + sendKey(KEYCODE_POWER); + + mPhoneWindowManager.assertNoDoublePowerLaunch(); + assertEquals(getDownKeysDispatched(), 3); + assertEquals(getUpKeysDispatched(), 3); + } + + /** + * Tests single press when window doesn't handle the power key. Phone should go to sleep. + */ + @Test + @EnableFlags(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public void testPowerSinglePress_windowHasOverridePermissionAndKeyUnhandledByApp() { + mPhoneWindowManager.overrideCanWindowOverridePowerKey(true); + setDispatchedKeyHandler(keyEvent -> false); + mPhoneWindowManager.overrideShortPressOnPower(SHORT_PRESS_POWER_GO_TO_SLEEP); + + sendKey(KEYCODE_POWER); + + mPhoneWindowManager.assertPowerSleep(); + } + + /** + * Tests single press when the window handles the power key. Phone should go to sleep after a + * delay of {POWER_MULTI_PRESS_TIMEOUT_MILLIS} + */ + @Test + @EnableFlags(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public void testPowerSinglePress_windowHasOverridePermissionAndKeyHandledByApp() { + mPhoneWindowManager.overrideCanWindowOverridePowerKey(true); + setDispatchedKeyHandler(keyEvent -> true); + mPhoneWindowManager.overrideDisplayState(Display.STATE_ON); + mPhoneWindowManager.overrideShortPressOnPower(SHORT_PRESS_POWER_GO_TO_SLEEP); + + sendKey(KEYCODE_POWER); + + mPhoneWindowManager.moveTimeForward(POWER_MULTI_PRESS_TIMEOUT_MILLIS); + + mPhoneWindowManager.assertPowerSleep(); + } + + + /** + * Tests 5x press when the window handles the power key. Emergency gesture should still be + * launched. + */ + @Test + @EnableFlags(FLAG_OVERRIDE_POWER_KEY_BEHAVIOR_IN_FOCUSED_WINDOW) + public void testPowerFiveTimesPress_windowHasOverridePermissionAndKeyHandledByApp() { + mPhoneWindowManager.overrideCanWindowOverridePowerKey(true); + setDispatchedKeyHandler(keyEvent -> true); + mPhoneWindowManager.overrideDisplayState(Display.STATE_ON); + mPhoneWindowManager.overrideShortPressOnPower(SHORT_PRESS_POWER_GO_TO_SLEEP); + + for (int i = 0; i < 5; ++i) { + sendKey(KEYCODE_POWER); + mPhoneWindowManager.moveTimeForward(100); + } + + mPhoneWindowManager.assertEmergencyLaunch(); + assertEquals(getDownKeysDispatched(), 2); + assertEquals(getUpKeysDispatched(), 2); + } } diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java index 9e47a008592c..2329a0728baf 100644 --- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java +++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java @@ -85,7 +85,11 @@ class ShortcutKeyTestBase { private Resources mResources; private PackageManager mPackageManager; TestPhoneWindowManager mPhoneWindowManager; - DispatchedKeyHandler mDispatchedKeyHandler = event -> false; + + DispatchedKeyHandler mDispatchedKeyHandler; + private int mDownKeysDispatched; + private int mUpKeysDispatched; + Context mContext; /** Modifier key to meta state */ @@ -116,6 +120,9 @@ class ShortcutKeyTestBase { XmlResourceParser testBookmarks = mResources.getXml( com.android.frameworks.wmtests.R.xml.bookmarks); doReturn(testBookmarks).when(mResources).getXml(com.android.internal.R.xml.bookmarks); + mDispatchedKeyHandler = event -> false; + mDownKeysDispatched = 0; + mUpKeysDispatched = 0; try { // Keep packageName / className in sync with @@ -229,6 +236,10 @@ class ShortcutKeyTestBase { sendKeyCombination(new int[]{keyCode}, 0 /*durationMillis*/, longPress, DEFAULT_DISPLAY); } + void sendKey(int keyCode, long durationMillis) { + sendKeyCombination(new int[]{keyCode}, durationMillis, false, DEFAULT_DISPLAY); + } + boolean sendKeyGestureEventStart(int gestureType) { return mPhoneWindowManager.sendKeyGestureEvent( new KeyGestureEvent.Builder().setKeyGestureType(gestureType).setAction( @@ -278,6 +289,14 @@ class ShortcutKeyTestBase { doReturn(expectedBehavior).when(mResources).getInteger(eq(resId)); } + int getDownKeysDispatched() { + return mDownKeysDispatched; + } + + int getUpKeysDispatched() { + return mUpKeysDispatched; + } + private void interceptKey(KeyEvent keyEvent) { int actions = mPhoneWindowManager.interceptKeyBeforeQueueing(keyEvent); if ((actions & ACTION_PASS_TO_USER) != 0) { @@ -285,6 +304,11 @@ class ShortcutKeyTestBase { if (!mDispatchedKeyHandler.onKeyDispatched(keyEvent)) { mPhoneWindowManager.interceptUnhandledKey(keyEvent); } + if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) { + ++mDownKeysDispatched; + } else { + ++mUpKeysDispatched; + } } } mPhoneWindowManager.dispatchAllPendingEvents(); diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java index 9db76d47fed7..f06b45e94f77 100644 --- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java @@ -22,6 +22,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.STATE_ON; import static android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE; +import static com.android.hardware.input.Flags.overridePowerKeyBehaviorInFocusedWindow; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong; @@ -45,10 +46,14 @@ import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_SHUT import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_MUTE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.after; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.description; import static org.mockito.Mockito.mockingDetails; import static org.mockito.Mockito.timeout; @@ -85,7 +90,9 @@ import android.os.VibratorInfo; import android.os.test.TestLooper; import android.provider.Settings; import android.service.dreams.DreamManagerInternal; +import android.service.quickaccesswallet.QuickAccessWalletClient; import android.telecom.TelecomManager; +import android.util.MutableBoolean; import android.view.Display; import android.view.InputEvent; import android.view.KeyCharacterMap; @@ -95,9 +102,12 @@ import android.view.autofill.AutofillManagerInternal; import com.android.dx.mockito.inline.extended.StaticMockitoSession; import com.android.internal.accessibility.AccessibilityShortcutController; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.internal.policy.KeyInterceptionInfo; import com.android.server.GestureLauncherService; import com.android.server.LocalServices; +import com.android.server.SystemService; import com.android.server.input.InputManagerInternal; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.pm.UserManagerInternal; @@ -120,6 +130,7 @@ import org.mockito.MockSettings; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.quality.Strictness; +import org.mockito.stubbing.Answer; import java.util.List; import java.util.function.Supplier; @@ -132,6 +143,8 @@ class TestPhoneWindowManager { private PhoneWindowManager mPhoneWindowManager; private Context mContext; + private GestureLauncherService mGestureLauncherService; + @Mock private WindowManagerInternal mWindowManagerInternal; @Mock private ActivityManagerInternal mActivityManagerInternal; @@ -163,7 +176,9 @@ class TestPhoneWindowManager { @Mock private DisplayRotation mDisplayRotation; @Mock private DisplayPolicy mDisplayPolicy; @Mock private WindowManagerPolicy.ScreenOnListener mScreenOnListener; - @Mock private GestureLauncherService mGestureLauncherService; + @Mock private QuickAccessWalletClient mQuickAccessWalletClient; + @Mock private MetricsLogger mMetricsLogger; + @Mock private UiEventLogger mUiEventLogger; @Mock private GlobalActions mGlobalActions; @Mock private AccessibilityShortcutController mAccessibilityShortcutController; @@ -192,6 +207,8 @@ class TestPhoneWindowManager { private int mKeyEventPolicyFlags = FLAG_INTERACTIVE; + private int mProcessPowerKeyDownCount = 0; + private class TestTalkbackShortcutController extends TalkbackShortcutController { TestTalkbackShortcutController(Context context) { super(context); @@ -260,6 +277,8 @@ class TestPhoneWindowManager { MockitoAnnotations.initMocks(this); mHandler = new Handler(mTestLooper.getLooper()); mContext = mockingDetails(context).isSpy() ? context : spy(context); + mGestureLauncherService = spy(new GestureLauncherService(mContext, mMetricsLogger, + mQuickAccessWalletClient, mUiEventLogger)); setUp(supportSettingsUpdate); mTestLooper.dispatchAll(); } @@ -272,6 +291,7 @@ class TestPhoneWindowManager { mMockitoSession = mockitoSession() .mockStatic(LocalServices.class, spyStubOnly) .mockStatic(KeyCharacterMap.class) + .mockStatic(GestureLauncherService.class) .strictness(Strictness.LENIENT) .startMocking(); @@ -294,6 +314,16 @@ class TestPhoneWindowManager { () -> LocalServices.getService(eq(PowerManagerInternal.class))); doReturn(mDisplayManagerInternal).when( () -> LocalServices.getService(eq(DisplayManagerInternal.class))); + doReturn(true).when( + () -> GestureLauncherService.isCameraDoubleTapPowerSettingEnabled(any(), anyInt()) + ); + doReturn(true).when( + () -> GestureLauncherService.isEmergencyGestureSettingEnabled(any(), anyInt()) + ); + doReturn(true).when( + () -> GestureLauncherService.isGestureLauncherEnabled(any()) + ); + mGestureLauncherService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); doReturn(mGestureLauncherService).when( () -> LocalServices.getService(eq(GestureLauncherService.class))); doReturn(mUserManagerInternal).when( @@ -375,7 +405,8 @@ class TestPhoneWindowManager { doNothing().when(mContext).startActivityAsUser(any(), any()); doNothing().when(mContext).startActivityAsUser(any(), any(), any()); - KeyInterceptionInfo interceptionInfo = new KeyInterceptionInfo(0, 0, null, 0); + KeyInterceptionInfo interceptionInfo = new KeyInterceptionInfo(0, 0, null, 0, + /* inputFeatureFlags = */ 0); doReturn(interceptionInfo) .when(mWindowManagerInternal).getKeyInterceptionInfoFromToken(any()); @@ -393,6 +424,8 @@ class TestPhoneWindowManager { eq(TEST_BROWSER_ROLE_PACKAGE_NAME)); doReturn(mSmsIntent).when(mPackageManager).getLaunchIntentForPackage( eq(TEST_SMS_ROLE_PACKAGE_NAME)); + mProcessPowerKeyDownCount = 0; + captureProcessPowerKeyDownCount(); Mockito.reset(mContext); } @@ -638,6 +671,12 @@ class TestPhoneWindowManager { .when(mButtonOverridePermissionChecker).canAppOverrideSystemKey(any(), anyInt()); } + void overrideCanWindowOverridePowerKey(boolean granted) { + doReturn(granted) + .when(mButtonOverridePermissionChecker).canWindowOverridePowerKey(any(), anyInt(), + anyInt()); + } + void overrideKeyEventPolicyFlags(int flags) { mKeyEventPolicyFlags = flags; } @@ -713,13 +752,59 @@ class TestPhoneWindowManager { verify(mPowerManager, never()).goToSleep(anyLong(), anyInt(), anyInt()); } - void assertCameraLaunch() { + void assertDoublePowerLaunch() { + ArgumentCaptor<MutableBoolean> valueCaptor = ArgumentCaptor.forClass(MutableBoolean.class); + mTestLooper.dispatchAll(); - // GestureLauncherService should receive interceptPowerKeyDown twice. - verify(mGestureLauncherService, times(2)) - .interceptPowerKeyDown(any(), anyBoolean(), any()); + verify(mGestureLauncherService, atLeast(2)) + .interceptPowerKeyDown(any(), anyBoolean(), valueCaptor.capture()); + verify(mGestureLauncherService, atMost(4)) + .interceptPowerKeyDown(any(), anyBoolean(), valueCaptor.capture()); + + if (overridePowerKeyBehaviorInFocusedWindow()) { + assertTrue(mProcessPowerKeyDownCount >= 2 && mProcessPowerKeyDownCount <= 4); + } + + List<Boolean> capturedValues = valueCaptor.getAllValues().stream() + .map(mutableBoolean -> mutableBoolean.value) + .toList(); + + assertTrue(capturedValues.contains(true)); } + void assertNoDoublePowerLaunch() { + ArgumentCaptor<MutableBoolean> valueCaptor = ArgumentCaptor.forClass(MutableBoolean.class); + + mTestLooper.dispatchAll(); + verify(mGestureLauncherService, atLeast(0)) + .interceptPowerKeyDown(any(), anyBoolean(), valueCaptor.capture()); + + List<Boolean> capturedValues = valueCaptor.getAllValues().stream() + .map(mutableBoolean -> mutableBoolean.value) + .toList(); + + assertTrue(capturedValues.stream().noneMatch(value -> value)); + } + + void assertEmergencyLaunch() { + ArgumentCaptor<MutableBoolean> valueCaptor = ArgumentCaptor.forClass(MutableBoolean.class); + + mTestLooper.dispatchAll(); + verify(mGestureLauncherService, atLeast(1)) + .interceptPowerKeyDown(any(), anyBoolean(), valueCaptor.capture()); + + if (overridePowerKeyBehaviorInFocusedWindow()) { + assertEquals(mProcessPowerKeyDownCount, 5); + } + + List<Boolean> capturedValues = valueCaptor.getAllValues().stream() + .map(mutableBoolean -> mutableBoolean.value) + .toList(); + + assertTrue(capturedValues.getLast()); + } + + void assertSearchManagerLaunchAssist() { mTestLooper.dispatchAll(); verify(mSearchManager).launchAssist(any()); @@ -929,4 +1014,12 @@ class TestPhoneWindowManager { verify(mInputManagerInternal) .handleKeyGestureInKeyGestureController(anyInt(), any(), anyInt(), eq(gestureType)); } + + private void captureProcessPowerKeyDownCount() { + doAnswer((Answer<Void>) invocation -> { + invocation.callRealMethod(); + mProcessPowerKeyDownCount++; + return null; + }).when(mGestureLauncherService).processPowerKeyDown(any()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java index 2a53df9f8353..a7fc10f2fcc5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java @@ -17,30 +17,23 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.SnapshotPersistQueue.MAX_STORE_QUEUE_DEPTH; 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; import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import android.content.ComponentName; -import android.graphics.ColorSpace; -import android.graphics.Point; -import android.graphics.Rect; -import android.hardware.HardwareBuffer; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; -import android.view.Surface; import android.window.TaskSnapshot; import androidx.test.filters.SmallTest; @@ -61,14 +54,20 @@ import java.util.Arrays; @SmallTest @Presubmit @RunWith(WindowTestRunner.class) -public class ActivitySnapshotControllerTests extends WindowTestsBase { +public class ActivitySnapshotControllerTests extends TaskSnapshotPersisterTestBase { private ActivitySnapshotController mActivitySnapshotController; + public ActivitySnapshotControllerTests() { + super(0.8f /* highResScale */, 0.5f /* lowResScale */); + } + + @Override @Before - public void setUp() throws Exception { - spyOn(mWm.mSnapshotController.mActivitySnapshotController); - mActivitySnapshotController = mWm.mSnapshotController.mActivitySnapshotController; + public void setUp() { + super.setUp(); + mActivitySnapshotController = new ActivitySnapshotController(mWm, mSnapshotPersistQueue); + spyOn(mActivitySnapshotController); doReturn(false).when(mActivitySnapshotController).shouldDisableSnapshots(); mActivitySnapshotController.resetTmpFields(); } @@ -92,12 +91,11 @@ public class ActivitySnapshotControllerTests extends WindowTestsBase { assertEquals(0, mActivitySnapshotController.mPendingRemoveActivity.size()); mActivitySnapshotController.resetTmpFields(); - // simulate three activity + // simulate three activity, the bottom activity won't participate in transition final WindowState belowClose = createAppWindow(task, ACTIVITY_TYPE_STANDARD, "belowClose"); belowClose.mActivityRecord.commitVisibility( false /* visible */, true /* performLayout */); - windows.add(belowClose.mActivityRecord); mActivitySnapshotController.handleTransitionFinish(windows); assertEquals(1, mActivitySnapshotController.mPendingRemoveActivity.size()); assertEquals(belowClose.mActivityRecord, @@ -249,15 +247,28 @@ public class ActivitySnapshotControllerTests extends WindowTestsBase { assertEquals(taskSnapshot, mActivitySnapshotController.getSnapshot(activities)); } - private TaskSnapshot createSnapshot() { - HardwareBuffer buffer = mock(HardwareBuffer.class); - doReturn(100).when(buffer).getWidth(); - doReturn(100).when(buffer).getHeight(); - return new TaskSnapshot(1, 0 /* captureTime */, new ComponentName("", ""), buffer, - ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, - Surface.ROTATION_0, new Point(100, 100), new Rect() /* contentInsets */, - new Rect() /* letterboxInsets*/, false /* isLowResolution */, - true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* mSystemUiVisibility */, - false /* isTranslucent */, false /* hasImeSurface */, 0 /* uiMode */); + /** + * Verifies that activity snapshot is skipped if the persister queue has too many pending write + * items. + */ + @Test + public void testSkipRecordActivity() { + doReturn(createSnapshot()).when(mActivitySnapshotController).recordSnapshotInner(any()); + final Task task = createTask(mDisplayContent); + + mSnapshotPersistQueue.setPaused(true); + final ArrayList<ActivityRecord> tmpList = new ArrayList<>(); + for (int i = 0; i < MAX_STORE_QUEUE_DEPTH; ++i) { + tmpList.clear(); + final ActivityRecord activity = createActivityRecord(task); + tmpList.add(activity); + mActivitySnapshotController.recordSnapshot(tmpList); + assertNotNull(mActivitySnapshotController.findSavedFile(activity)); + } + tmpList.clear(); + final ActivityRecord activity = createActivityRecord(task); + tmpList.add(activity); + mActivitySnapshotController.recordSnapshot(tmpList); + assertNull(mActivitySnapshotController.findSavedFile(activity)); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java index d183cf720491..f3a2e86fe6db 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContextListenerControllerTests.java @@ -46,6 +46,7 @@ import android.app.servertransaction.WindowContextInfoChangeItem; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.Display; import android.view.DisplayInfo; @@ -54,7 +55,12 @@ import android.window.WindowTokenClient; import androidx.test.filters.SmallTest; +import com.android.window.flags.Flags; + +import com.google.common.truth.Expect; + import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -65,6 +71,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; + /** * Build/Install/Run: * atest WmTests:WindowContextListenerControllerTests @@ -86,6 +93,9 @@ public class WindowContextListenerControllerTests extends WindowTestsBase { private WindowProcessController mWpc; private WindowContainer<?> mContainer; + @Rule + public final Expect mExpect = Expect.create(); + @Before public void setUp() { initMocks(this); @@ -341,6 +351,30 @@ public class WindowContextListenerControllerTests extends WindowTestsBase { assertThat(clientToken.mDisplayId).isEqualTo(mDisplayContent.mDisplayId); } + @Test + @EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void assertCallerCanReparentListener_returnsTrueWhenExpected() { + mController.registerWindowContainerListener(mWpc, mClientToken, mContainer, + TYPE_APPLICATION_OVERLAY, null /* options */); + + // Here there are several checks in one test as wm tests are expensive. + + // Correct conditions -> returns true + mExpect.that(mController.assertCallerCanReparentListener(mClientToken, + /* callerCanManageAppTokens= */ true, + /* callingUid= */ mWpc.mUid, + /* displayId= */ DEFAULT_DISPLAY + 1 + )).isTrue(); + + // sameDisplayId (so, container already attached) -> returnsFalse + mExpect.that(mController.assertCallerCanReparentListener( + mClientToken, + /* callerCanManageAppTokens= */ true, + /* callingUid= */ mWpc.mUid, + /* displayId= */ DEFAULT_DISPLAY // <- same display ID + )).isFalse(); + } + private static class TestWindowTokenClient extends WindowTokenClient { private Configuration mConfiguration; private int mDisplayId; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index bfa6cb820a42..69df66ee783b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -39,6 +39,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_ import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION; import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; @@ -70,6 +71,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.description; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -86,10 +88,10 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.ArraySet; import android.util.MergedConfiguration; import android.view.ContentRecordingSession; @@ -151,9 +153,6 @@ public class WindowManagerServiceTests extends WindowTestsBase { @Rule public Expect mExpect = Expect.create(); - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - @After public void tearDown() { mWm.mSensitiveContentPackages.clearBlockedApps(); @@ -1412,6 +1411,84 @@ public class WindowManagerServiceTests extends WindowTestsBase { assertThat(result).isEqualTo(WindowManagerGlobal.ADD_INVALID_DISPLAY); } + /** Mocks some deps to associate a display content to a specific display id. */ + private void setupReparentWindowContextToDisplayAreaTest(WindowToken windowToken, + DisplayContent dc, int displayId) { + spyOn(mWm.mWindowContextListenerController); + doReturn(dc).when(mWm.mRoot).getDisplayContentOrCreate(displayId); + doReturn(true).when(mWm.mWindowContextListenerController).assertCallerCanReparentListener( + any(), anyBoolean(), anyInt(), eq(displayId)); + doReturn(windowToken).when(mWm.mWindowContextListenerController).getContainer( + eq(windowToken.token)); + } + + @Test + @EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void reparentWindowContextToDisplayArea_newDisplay_reparented() { + final WindowToken windowToken = createTestClientWindowToken(TYPE_NOTIFICATION_SHADE, + mDisplayContent); + final int newDisplayId = 1; + final DisplayContent dc = createNewDisplay(); + setupReparentWindowContextToDisplayAreaTest(windowToken, dc, newDisplayId); + + assertThat(windowToken.getDisplayContent()).isEqualTo(mDisplayContent); + + assertThat(mWm.reparentWindowContextToDisplayArea(mAppThread, windowToken.token, + newDisplayId)).isTrue(); + + assertThat(windowToken.getDisplayContent()).isNotEqualTo(mDisplayContent); + } + + @Test + @DisableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void reparentWindowContextToDisplayArea_newDisplayButFlagDisabled_notReparented() { + final WindowToken windowToken = createTestClientWindowToken(TYPE_NOTIFICATION_SHADE, + mDisplayContent); + final int newDisplayId = 1; + final DisplayContent dc = createNewDisplay(); + setupReparentWindowContextToDisplayAreaTest(windowToken, dc, newDisplayId); + + assertThat(mWm.reparentWindowContextToDisplayArea(mAppThread, windowToken.token, + newDisplayId)).isFalse(); + + assertThat(windowToken.getDisplayContent()).isEqualTo(mDisplayContent); + } + + @Test + @EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void reparentWindowContext_afterReparent_DCNeedsLayout() { + final WindowToken windowToken = createTestClientWindowToken(TYPE_NOTIFICATION_SHADE, + mDisplayContent); + final int newDisplayId = 1; + final DisplayContent dc = createNewDisplay(); + setupReparentWindowContextToDisplayAreaTest(windowToken, dc, newDisplayId); + + assertThat(mWm.reparentWindowContextToDisplayArea(mAppThread, windowToken.token, + newDisplayId)).isTrue(); + + assertThat(dc.isLayoutNeeded()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void reparentWindowContext_afterReparent_traversalScheduled() { + final WindowToken windowToken = createTestClientWindowToken(TYPE_NOTIFICATION_SHADE, + mDisplayContent); + final int newDisplayId = 1; + final DisplayContent dc = createNewDisplay(); + setupReparentWindowContextToDisplayAreaTest(windowToken, dc, newDisplayId); + spyOn(mWm.mWindowPlacerLocked); + reset(mWm.mWindowPlacerLocked); + + verify(mWm.mWindowPlacerLocked, never()).requestTraversal(); + + assertThat(mWm.reparentWindowContextToDisplayArea(mAppThread, windowToken.token, + newDisplayId)).isTrue(); + + verify(mWm.mWindowPlacerLocked).requestTraversal(); + } + + class TestResultReceiver implements IResultReceiver { public android.os.Bundle resultData; private final IBinder mBinder = mock(IBinder.class); 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 78e6cbf9c36a..3a97cc621e0d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -2039,9 +2039,22 @@ public class WindowTestsBase extends SystemServiceTestsBase { return new TestWindowToken(type, dc, persistOnEmpty); } + static TestWindowToken createTestClientWindowToken(int type, DisplayContent dc) { + SystemServicesTestRule.checkHoldsLock(dc.mWmService.mGlobalLock); + + return new TestWindowToken(type, dc, false /* persistOnEmpty */, true /* fromClient */); + } + /** Used so we can gain access to some protected members of the {@link WindowToken} class */ static class TestWindowToken extends WindowToken { + private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty, + boolean fromClient) { + super(dc.mWmService, mock(IBinder.class), type, persistOnEmpty, dc, + false /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */, + fromClient /* fromClientToken */, null /* options */); + } + private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { super(dc.mWmService, mock(IBinder.class), type, persistOnEmpty, dc, false /* ownerCanManageAppTokens */); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index 35328a0e1dc0..f226b9d29ca0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -33,21 +33,27 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.view.WindowInsets; import android.window.WindowContext; import androidx.test.filters.SmallTest; +import com.android.window.flags.Flags; + import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; import java.util.function.BiFunction; @@ -304,14 +310,39 @@ public class WindowTokenTests extends WindowTestsBase { // immediately. verify the window will hide without applying exit animation. mWm.removeWindowToken(win.mToken.token, false /* removeWindows */, false /* animateExit */, mDisplayContent.mDisplayId); - verify(win).onSetAppExiting(Mockito.eq(false) /* animateExit */); + verify(win).onSetAppExiting(eq(false) /* animateExit */); verify(win).hide(false /* doAnimation */, false /* requestAnim */); assertFalse(win.isOnScreen()); - verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false); + verify(win.mWinAnimator, never()).applyAnimationLocked(TRANSIT_EXIT, false); assertTrue(win.mToken.hasChild()); // Even though the window is being removed afterwards, it won't apply exit animation. win.removeIfPossible(); - verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false); + verify(win.mWinAnimator, never()).applyAnimationLocked(TRANSIT_EXIT, false); + } + + @Test + @EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void onDisplayChanged_differentDisplay_reparented() { + final TestWindowToken token = createTestWindowToken(0, mDisplayContent); + final DisplayContent dc = mock(DisplayContent.class); + when(dc.getWindowToken(any())).thenReturn(null); // dc doesn't have this window token. + + token.onDisplayChanged(dc); + + verify(dc).reParentWindowToken(eq(token)); + } + + @Test + @EnableFlags(Flags.FLAG_REPARENT_WINDOW_TOKEN_API) + public void onDisplayChanged_samedisplay_notReparented() { + + final TestWindowToken token = createTestWindowToken(0, mDisplayContent); + final DisplayContent dc = mock(DisplayContent.class); + when(dc.getWindowToken(any())).thenReturn(mock(WindowToken.class)); + + token.onDisplayChanged(dc); + + verify(dc, never()).reParentWindowToken(eq(token)); } } diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java index a69dfb0b255f..cdb3eaf46def 100644 --- a/telecomm/java/android/telecom/ParcelableCallAnalytics.java +++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.java @@ -16,12 +16,12 @@ package android.telecom; +import android.annotation.FlaggedApi; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; -import java.util.LinkedList; import java.util.List; /** @@ -255,6 +255,11 @@ public class ParcelableCallAnalytics implements Parcelable { public static final int CALLTYPE_OUTGOING = 2; // Constants for call technology + /** + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(com.android.internal.telephony.flags.Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_PHONE = 0x1; public static final int GSM_PHONE = 0x2; public static final int IMS_PHONE = 0x4; diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index 8fe107cc1ad3..09b18b65be4a 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -109,6 +109,7 @@ public class Annotation { //TelephonyManager.NETWORK_TYPE_LTE_CA, TelephonyManager.NETWORK_TYPE_NR, + TelephonyManager.NETWORK_TYPE_NB_IOT_NTN, }) @Retention(RetentionPolicy.SOURCE) public @interface NetworkType { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index e5f1841de641..478ec5c62bc6 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -317,8 +317,10 @@ public class CarrierConfigManager { * If this is set as false and the supplementary service menu is visible, the associated setting * will be enabled and disabled based on the availability of supplementary services over UT. See * {@link #KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_SUPPORT_SS_OVER_CDMA_BOOL = "support_ss_over_cdma_bool"; /** @@ -536,7 +538,11 @@ public class CarrierConfigManager { */ public static final String KEY_4G_ONLY_BOOL = "4g_only_bool"; - /** Show cdma network mode choices 1x, 3G, global etc. */ + /** Show cdma network mode choices 1x, 3G, global etc. + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool"; /** CDMA activation goes through HFA */ @@ -544,9 +550,12 @@ public class CarrierConfigManager { /** * CDMA activation goes through OTASP. + * @deprecated Legacy CDMA is unsupported. */ // TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum // (NONE, HFA, OTASP). + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; @@ -556,10 +565,20 @@ public class CarrierConfigManager { /** Does not display additional call setting for IMS phone based on GSM Phone */ public static final String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool"; - /** Show APN Settings for some CDMA carriers */ + /** + * Show APN Settings for some CDMA carriers + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; - /** After a CDMA conference call is merged, the swap button should be displayed. */ + /** + * After a CDMA conference call is merged, the swap button should be displayed. + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool"; /** @@ -597,7 +616,10 @@ public class CarrierConfigManager { /** * Disables dialing "*228" (OTASP provisioning) on CDMA carriers where it is not supported or is * potentially harmful by locking the SIM to 3G. + * @deprecated Legacy CDMA is unsupported. */ + @Deprecated + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; @@ -675,14 +697,20 @@ public class CarrierConfigManager { /** * Override the platform's notion of a network operator being considered roaming. * Value is string array of SIDs to be considered roaming for 3GPP2 RATs. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; /** * Override the platform's notion of a network operator being considered non roaming. * Value is string array of SIDs to be considered not roaming for 3GPP2 RATs. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; @@ -1243,8 +1271,10 @@ public class CarrierConfigManager { /** * CDMA carrier ERI (Enhanced Roaming Indicator) file name + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_CARRIER_ERI_FILE_NAME_STRING = "carrier_eri_file_name_string"; /* The following 3 fields are related to carrier visual voicemail. */ @@ -1386,7 +1416,10 @@ public class CarrierConfigManager { * Specifies the amount of gap to be added in millis between postdial DTMF tones. When a * non-zero value is specified, the UE shall wait for the specified amount of time before it * sends out successive DTMF tones on the network. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int"; /** @@ -1804,8 +1837,10 @@ public class CarrierConfigManager { * If this bit is not set, the carrier name display string will be selected from the carrier * display name resolver which doesn't apply the ERI rules. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_ALLOW_ERI_BOOL = "allow_cdma_eri_bool"; /** @@ -1849,8 +1884,10 @@ public class CarrierConfigManager { * If true, then the registered PLMN name (only for CDMA/CDMA-LTE and only when not roaming) * will be #KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING. If false, or if phone type is not * CDMA/CDMA-LTE or if roaming, then #KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING will be ignored. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_CDMA_HOME_REGISTERED_PLMN_NAME_OVERRIDE_BOOL = "cdma_home_registered_plmn_name_override_bool"; @@ -1858,8 +1895,10 @@ public class CarrierConfigManager { * String to identify registered PLMN name in CarrierConfig app. This string overrides * registered PLMN name if #KEY_CDMA_HOME_REGISTERED_PLMN_NAME_OVERRIDE_BOOL is true, phone type * is CDMA/CDMA-LTE and device is not in roaming state; otherwise, it will be ignored. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING = "cdma_home_registered_plmn_name_string"; @@ -2440,7 +2479,10 @@ public class CarrierConfigManager { * For carriers which require an empty flash to be sent before sending the normal 3-way calling * flash, the duration in milliseconds of the empty flash to send. When {@code 0}, no empty * flash is sent. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int"; /** @@ -2454,14 +2496,21 @@ public class CarrierConfigManager { * @see TelephonyManager#CDMA_ROAMING_MODE_HOME * @see TelephonyManager#CDMA_ROAMING_MODE_AFFILIATED * @see TelephonyManager#CDMA_ROAMING_MODE_ANY + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int"; /** * Determines whether 1X voice calls is supported for some CDMA carriers. * Default value is true. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool"; @@ -2483,8 +2532,10 @@ public class CarrierConfigManager { /** * Report IMEI as device id even if it's a CDMA/LTE phone. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_FORCE_IMEI_BOOL = "force_imei_bool"; /** @@ -3217,8 +3268,10 @@ public class CarrierConfigManager { * on a 3GPP network. Specifically *67<number> will be converted to #31#<number> and * *82<number> will be converted to *31#<number> before dialing a call when this key is * set TRUE and device is roaming on a 3GPP network. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL = "convert_cdma_caller_id_mmi_codes_while_roaming_on_3gpp_bool"; @@ -3621,8 +3674,11 @@ public class CarrierConfigManager { /** * Support for the original string display of CDMA MO call. * By default, it is disabled. + * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_CONFIG_SHOW_ORIG_DIAL_STRING_FOR_CDMA_BOOL = "config_show_orig_dial_string_for_cdma"; @@ -5070,8 +5126,10 @@ public class CarrierConfigManager { * The default values come from 3GPP2 C.R1001 table 8.1-1. * Enhanced Roaming Indicator Number Assignments * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY = "cdma_enhanced_roaming_indicator_for_home_network_int_array"; diff --git a/telephony/java/android/telephony/CellBroadcastService.java b/telephony/java/android/telephony/CellBroadcastService.java index 14de2f285756..60f986c684fe 100644 --- a/telephony/java/android/telephony/CellBroadcastService.java +++ b/telephony/java/android/telephony/CellBroadcastService.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.CallSuper; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -28,6 +29,7 @@ import android.os.IBinder; import android.os.RemoteCallback; import android.telephony.cdma.CdmaSmsCbProgramData; +import com.android.internal.telephony.flags.Flags; import com.android.internal.util.FastPrintWriter; import java.io.FileDescriptor; @@ -88,9 +90,12 @@ public abstract class CellBroadcastService extends Service { * @param slotIndex the index of the slot which received the message * @param bearerData the CDMA SMS bearer data * @param serviceCategory the CDMA SCPT service category + * @deprecated Legacy CDMA is unsupported. */ - public abstract void onCdmaCellBroadcastSms(int slotIndex, @NonNull byte[] bearerData, - @CdmaSmsCbProgramData.Category int serviceCategory); + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated + public void onCdmaCellBroadcastSms(int slotIndex, @NonNull byte[] bearerData, + @CdmaSmsCbProgramData.Category int serviceCategory) {} /** * Handle a CDMA cell broadcast SMS message forwarded from the system. @@ -102,10 +107,13 @@ public abstract class CellBroadcastService extends Service { * @param callback a callback to run after each cell broadcast receiver has handled * the SCP message. The bundle will contain a non-separated * dial string as and an ArrayList of {@link CdmaSmsCbProgramResults}. + * @deprecated Legacy CDMA is unsupported. */ - public abstract void onCdmaScpMessage(int slotIndex, + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated + public void onCdmaScpMessage(int slotIndex, @NonNull List<CdmaSmsCbProgramData> smsCbProgramData, - @NonNull String originatingAddress, @NonNull Consumer<Bundle> callback); + @NonNull String originatingAddress, @NonNull Consumer<Bundle> callback) {} /** * Get broadcasted area information. diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index 5eace5433128..4e5a246ef773 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -18,11 +18,13 @@ package android.telephony; import static android.text.TextUtils.formatSimple; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.telephony.cdma.CdmaCellLocation; +import com.android.internal.telephony.flags.Flags; import com.android.internal.telephony.util.TelephonyUtils; import com.android.telephony.Rlog; @@ -30,7 +32,11 @@ import java.util.Objects; /** * CellIdentity is to represent a unique CDMA cell + * + * @deprecated Legacy CDMA is unsupported. */ +@FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) +@Deprecated public final class CellIdentityCdma extends CellIdentity { private static final String TAG = CellIdentityCdma.class.getSimpleName(); private static final boolean DBG = false; @@ -124,7 +130,11 @@ public final class CellIdentityCdma extends CellIdentity { return new CellIdentityCdma(this); } - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public @NonNull CellIdentityCdma sanitizeLocationInfo() { return new CellIdentityCdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, @@ -157,7 +167,11 @@ public final class CellIdentityCdma extends CellIdentity { /** * @return Network Id 0..65535, {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} * if unavailable. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getNetworkId() { return mNetworkId; } @@ -165,7 +179,11 @@ public final class CellIdentityCdma extends CellIdentity { /** * @return System Id 0..32767, {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} * if unavailable. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getSystemId() { return mSystemId; } @@ -173,7 +191,10 @@ public final class CellIdentityCdma extends CellIdentity { /** * @return Base Station Id 0..65535, {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} * if unavailable. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getBasestationId() { return mBasestationId; } @@ -184,7 +205,11 @@ public final class CellIdentityCdma extends CellIdentity { * of 0.25 seconds and ranges from -2592000 to 2592000, both * values inclusive (corresponding to a range of -180 * to +180 degrees). {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getLongitude() { return mLongitude; } @@ -195,7 +220,11 @@ public final class CellIdentityCdma extends CellIdentity { * of 0.25 seconds and ranges from -1296000 to 1296000, both * values inclusive (corresponding to a range of -90 * to +90 degrees). {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public int getLatitude() { return mLatitude; } @@ -206,7 +235,11 @@ public final class CellIdentityCdma extends CellIdentity { super.hashCode()); } - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @NonNull @Override public CdmaCellLocation asCellLocation() { @@ -277,7 +310,13 @@ public final class CellIdentityCdma extends CellIdentity { if (DBG) log(toString()); } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SuppressWarnings("hiding") public static final @android.annotation.NonNull Creator<CellIdentityCdma> CREATOR = new Creator<CellIdentityCdma>() { diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java index aa8cff52bcaf..3c4bb5164ffc 100644 --- a/telephony/java/android/telephony/CellInfoCdma.java +++ b/telephony/java/android/telephony/CellInfoCdma.java @@ -16,17 +16,23 @@ package android.telephony; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.telephony.flags.Flags; import com.android.telephony.Rlog; /** * A {@link CellInfo} representing a CDMA cell that provides identity and measurement info. + * + * @deprecated Legacy CDMA is unsupported. */ +@FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) +@Deprecated public final class CellInfoCdma extends CellInfo implements Parcelable { private static final String LOG_TAG = "CellInfoCdma"; @@ -61,7 +67,10 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { /** * @return a {@link CellIdentityCdma} instance. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public @NonNull CellIdentityCdma getCellIdentity() { return mCellIdentityCdma; @@ -75,7 +84,10 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { /** * @return a {@link CellSignalStrengthCdma} instance. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public @NonNull CellSignalStrengthCdma getCellSignalStrength() { return mCellSignalStrengthCdma; @@ -135,7 +147,12 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { return 0; } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags, TYPE_CDMA); @@ -154,7 +171,12 @@ public final class CellInfoCdma extends CellInfo implements Parcelable { if (DBG) log("CellInfoCdma(Parcel): " + toString()); } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final @android.annotation.NonNull Creator<CellInfoCdma> CREATOR = new Creator<CellInfoCdma>() { @Override public CellInfoCdma createFromParcel(Parcel in) { diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java index d9437ab29881..2d650ab20802 100644 --- a/telephony/java/android/telephony/PreciseDisconnectCause.java +++ b/telephony/java/android/telephony/PreciseDisconnectCause.java @@ -255,25 +255,75 @@ public final class PreciseDisconnectCause { @FlaggedApi(Flags.FLAG_USE_OEM_DOMAIN_SELECTION_SERVICE) public static final int EMERGENCY_PERM_FAILURE = 326; - /** Mobile station (MS) is locked until next power cycle. */ + /** + * Mobile station (MS) is locked until next power cycle. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; - /** Drop call. */ + /** + * Drop call. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_DROP = 1001; - /** INTERCEPT order received, Mobile station (MS) state idle entered. */ + /** + * INTERCEPT order received, Mobile station (MS) state idle entered. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_INTERCEPT = 1002; - /** Mobile station (MS) has been redirected, call is cancelled. */ + /** + * Mobile station (MS) has been redirected, call is cancelled. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_REORDER = 1003; - /** Service option rejection. */ + /** + * Service option rejection. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_SO_REJECT = 1004; - /** Requested service is rejected, retry delay is set. */ + /** + * Requested service is rejected, retry delay is set. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_RETRY_ORDER = 1005; - /** Unable to obtain access to the CDMA system. */ + /** + * Unable to obtain access to the CDMA system. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ACCESS_FAILURE = 1006; - /** Not a preempted call. */ + /** + * Not a preempted call. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_PREEMPTED = 1007; - /** Not an emergency call. */ + /** + * Not an emergency call. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_NOT_EMERGENCY = 1008; - /** Access Blocked by CDMA network. */ + /** + * Access Blocked by CDMA network. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ACCESS_BLOCKED = 1009; /* OEM specific error codes. To be used by OEMs when they don't want to diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java index 90d6f89553b7..8b52f07102b8 100644 --- a/telephony/java/android/telephony/RadioAccessFamily.java +++ b/telephony/java/android/telephony/RadioAccessFamily.java @@ -66,6 +66,9 @@ public class RadioAccessFamily implements Parcelable { // 5G public static final int RAF_NR = (int) TelephonyManager.NETWORK_TYPE_BITMASK_NR; + /** NB-IOT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology. */ + public static final int RAF_NB_IOT_NTN = (int) TelephonyManager.NETWORK_TYPE_BITMASK_NB_IOT_NTN; + // Grouping of RAFs // 2G private static final int GSM = RAF_GSM | RAF_GPRS | RAF_EDGE; @@ -80,6 +83,9 @@ public class RadioAccessFamily implements Parcelable { // 5G private static final int NR = RAF_NR; + /** Non-Terrestrial Network. */ + private static final int NB_IOT_NTN = RAF_NB_IOT_NTN; + /* Phone ID of phone */ private int mPhoneId; @@ -258,7 +264,7 @@ public class RadioAccessFamily implements Parcelable { raf = ((EVDO & raf) > 0) ? (EVDO | raf) : raf; raf = ((LTE & raf) > 0) ? (LTE | raf) : raf; raf = ((NR & raf) > 0) ? (NR | raf) : raf; - + raf = ((NB_IOT_NTN & raf) > 0) ? (NB_IOT_NTN | raf) : raf; return raf; } @@ -364,6 +370,7 @@ public class RadioAccessFamily implements Parcelable { case "WCDMA": return WCDMA; case "LTE_CA": return RAF_LTE_CA; case "NR": return RAF_NR; + case "NB_IOT_NTN": return RAF_NB_IOT_NTN; default: return RAF_UNKNOWN; } } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 127bbff01575..f8c3287fec36 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -233,6 +233,12 @@ public class ServiceState implements Parcelable { public static final int RIL_RADIO_TECHNOLOGY_NR = 20; /** + * 3GPP NB-IOT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology. + * @hide + */ + public static final int RIL_RADIO_TECHNOLOGY_NB_IOT_NTN = 21; + + /** * RIL Radio Annotation * @hide */ @@ -258,14 +264,16 @@ public class ServiceState implements Parcelable { ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA, - ServiceState.RIL_RADIO_TECHNOLOGY_NR}) + ServiceState.RIL_RADIO_TECHNOLOGY_NR, + ServiceState.RIL_RADIO_TECHNOLOGY_NB_IOT_NTN + }) public @interface RilRadioTechnology {} /** * The number of the radio technologies. */ - private static final int NEXT_RIL_RADIO_TECHNOLOGY = 21; + private static final int NEXT_RIL_RADIO_TECHNOLOGY = 22; /** @hide */ public static final int RIL_RADIO_CDMA_TECHNOLOGY_BITMASK = @@ -1125,6 +1133,9 @@ public class ServiceState implements Parcelable { case RIL_RADIO_TECHNOLOGY_NR: rtString = "NR_SA"; break; + case RIL_RADIO_TECHNOLOGY_NB_IOT_NTN: + rtString = "NB_IOT_NTN"; + break; default: rtString = "Unexpected"; Rlog.w(LOG_TAG, "Unexpected radioTechnology=" + rt); @@ -1668,6 +1679,8 @@ public class ServiceState implements Parcelable { return TelephonyManager.NETWORK_TYPE_LTE_CA; case RIL_RADIO_TECHNOLOGY_NR: return TelephonyManager.NETWORK_TYPE_NR; + case RIL_RADIO_TECHNOLOGY_NB_IOT_NTN: + return TelephonyManager.NETWORK_TYPE_NB_IOT_NTN; default: return TelephonyManager.NETWORK_TYPE_UNKNOWN; } @@ -1697,6 +1710,7 @@ public class ServiceState implements Parcelable { return AccessNetworkType.CDMA2000; case RIL_RADIO_TECHNOLOGY_LTE: case RIL_RADIO_TECHNOLOGY_LTE_CA: + case RIL_RADIO_TECHNOLOGY_NB_IOT_NTN: return AccessNetworkType.EUTRAN; case RIL_RADIO_TECHNOLOGY_NR: return AccessNetworkType.NGRAN; @@ -1757,6 +1771,8 @@ public class ServiceState implements Parcelable { return RIL_RADIO_TECHNOLOGY_LTE_CA; case TelephonyManager.NETWORK_TYPE_NR: return RIL_RADIO_TECHNOLOGY_NR; + case TelephonyManager.NETWORK_TYPE_NB_IOT_NTN: + return RIL_RADIO_TECHNOLOGY_NB_IOT_NTN; default: return RIL_RADIO_TECHNOLOGY_UNKNOWN; } @@ -1866,7 +1882,8 @@ public class ServiceState implements Parcelable { || radioTechnology == RIL_RADIO_TECHNOLOGY_TD_SCDMA || radioTechnology == RIL_RADIO_TECHNOLOGY_IWLAN || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA - || radioTechnology == RIL_RADIO_TECHNOLOGY_NR; + || radioTechnology == RIL_RADIO_TECHNOLOGY_NR + || radioTechnology == RIL_RADIO_TECHNOLOGY_NB_IOT_NTN; } @@ -1886,7 +1903,8 @@ public class ServiceState implements Parcelable { public static boolean isPsOnlyTech(int radioTechnology) { return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA - || radioTechnology == RIL_RADIO_TECHNOLOGY_NR; + || radioTechnology == RIL_RADIO_TECHNOLOGY_NR + || radioTechnology == RIL_RADIO_TECHNOLOGY_NB_IOT_NTN; } /** @hide */ diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 65a52daae99f..698821bc8890 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1397,25 +1397,44 @@ public class TelephonyManager { /** * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which leaves the roaming * mode set to the radio default or to the user's preference if they've indicated one. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; /** * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which only permits * connections on home networks. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ROAMING_MODE_HOME = 0; /** * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which permits roaming on * affiliated networks. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; /** * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which permits roaming on * any network. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CDMA_ROAMING_MODE_ANY = 2; - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @IntDef(prefix = { "CDMA_ROAMING_MODE_" }, value = { CDMA_ROAMING_MODE_RADIO_DEFAULT, CDMA_ROAMING_MODE_HOME, @@ -1802,12 +1821,17 @@ public class TelephonyManager { * to indicate if the SIM combination in DSDS has limitation or compatible issue. * e.g. two CDMA SIMs may disrupt each other's voice call in certain scenarios. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final String EXTRA_SIM_COMBINATION_WARNING_TYPE = "android.telephony.extra.SIM_COMBINATION_WARNING_TYPE"; - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @IntDef({ EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE, EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA @@ -1818,15 +1842,21 @@ public class TelephonyManager { /** * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE} * to indicate there's no SIM combination warning. + * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE = 0; /** * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE} * to indicate two active SIMs are both CDMA hence there might be functional limitation. + * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA = 1; /** @@ -1835,6 +1865,7 @@ public class TelephonyManager { * e.g. two CDMA SIMs may disrupt each other's voice call in certain scenarios, and the * name will be "operator1 & operator2". * + * TODO(b/379356026): Deprecate if this is CDMA specific * @hide */ public static final String EXTRA_SIM_COMBINATION_NAMES = @@ -2414,9 +2445,12 @@ public class TelephonyManager { * higher, then a SecurityException is thrown.</li> * </ul> * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -2456,9 +2490,12 @@ public class TelephonyManager { * * @param slotIndex of which MEID is returned * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -2485,9 +2522,12 @@ public class TelephonyManager { * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not * available. * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @Nullable public String getManufacturerCode() { @@ -2500,9 +2540,12 @@ public class TelephonyManager { * * @param slotIndex of which Type Allocation Code is returned * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @Nullable public String getManufacturerCode(int slotIndex) { @@ -2648,7 +2691,13 @@ public class TelephonyManager { public static final int PHONE_TYPE_NONE = PhoneConstants.PHONE_TYPE_NONE; /** Phone radio is GSM. */ public static final int PHONE_TYPE_GSM = PhoneConstants.PHONE_TYPE_GSM; - /** Phone radio is CDMA. */ + /** + * Phone radio is CDMA. + * + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int PHONE_TYPE_CDMA = PhoneConstants.PHONE_TYPE_CDMA; /** Phone is via SIP. */ public static final int PHONE_TYPE_SIP = PhoneConstants.PHONE_TYPE_SIP; @@ -3070,13 +3119,33 @@ public class TelephonyManager { public static final int NETWORK_TYPE_EDGE = TelephonyProtoEnums.NETWORK_TYPE_EDGE; // = 2. /** Current network is UMTS */ public static final int NETWORK_TYPE_UMTS = TelephonyProtoEnums.NETWORK_TYPE_UMTS; // = 3. - /** Current network is CDMA: Either IS95A or IS95B*/ + /** + * Current network is CDMA: Either IS95A or IS95B + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_CDMA = TelephonyProtoEnums.NETWORK_TYPE_CDMA; // = 4. - /** Current network is EVDO revision 0*/ + /** + * Current network is EVDO revision 0 + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_EVDO_0 = TelephonyProtoEnums.NETWORK_TYPE_EVDO_0; // = 5. - /** Current network is EVDO revision A*/ + /** + * Current network is EVDO revision A + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_EVDO_A = TelephonyProtoEnums.NETWORK_TYPE_EVDO_A; // = 6. - /** Current network is 1xRTT*/ + /** + * Current network is 1xRTT + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_1xRTT = TelephonyProtoEnums.NETWORK_TYPE_1XRTT; // = 7. /** Current network is HSDPA */ public static final int NETWORK_TYPE_HSDPA = TelephonyProtoEnums.NETWORK_TYPE_HSDPA; // = 8. @@ -3090,11 +3159,21 @@ public class TelephonyManager { */ @Deprecated public static final int NETWORK_TYPE_IDEN = TelephonyProtoEnums.NETWORK_TYPE_IDEN; // = 11. - /** Current network is EVDO revision B*/ + /** + * Current network is EVDO revision B + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_EVDO_B = TelephonyProtoEnums.NETWORK_TYPE_EVDO_B; // = 12. /** Current network is LTE */ public static final int NETWORK_TYPE_LTE = TelephonyProtoEnums.NETWORK_TYPE_LTE; // = 13. - /** Current network is eHRPD */ + /** + * Current network is eHRPD + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int NETWORK_TYPE_EHRPD = TelephonyProtoEnums.NETWORK_TYPE_EHRPD; // = 14. /** Current network is HSPA+ */ public static final int NETWORK_TYPE_HSPAP = TelephonyProtoEnums.NETWORK_TYPE_HSPAP; // = 15. @@ -3114,6 +3193,12 @@ public class TelephonyManager { * For 5G NSA, the network type will be {@link #NETWORK_TYPE_LTE}. */ public static final int NETWORK_TYPE_NR = TelephonyProtoEnums.NETWORK_TYPE_NR; // 20. + /** + * 3GPP NB-IOT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology. + */ + @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS) + public static final int NETWORK_TYPE_NB_IOT_NTN = + TelephonyProtoEnums.NETWORK_TYPE_NB_IOT_NTN; // 21 private static final @NetworkType int[] NETWORK_TYPES = { NETWORK_TYPE_GPRS, @@ -3190,6 +3275,7 @@ public class TelephonyManager { * @see #NETWORK_TYPE_EHRPD * @see #NETWORK_TYPE_HSPAP * @see #NETWORK_TYPE_NR + * @see #NETWORK_TYPE_NB_IOT_NTN * * @hide */ @@ -3250,6 +3336,7 @@ public class TelephonyManager { * @see #NETWORK_TYPE_EHRPD * @see #NETWORK_TYPE_HSPAP * @see #NETWORK_TYPE_NR + * @see #NETWORK_TYPE_NB_IOT_NTN * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_RADIO_ACCESS}. @@ -3400,6 +3487,8 @@ public class TelephonyManager { return "LTE_CA"; case NETWORK_TYPE_NR: return "NR"; + case NETWORK_TYPE_NB_IOT_NTN: + return "NB_IOT_NTN"; case NETWORK_TYPE_UNKNOWN: return "UNKNOWN"; default: @@ -3450,6 +3539,8 @@ public class TelephonyManager { return NETWORK_TYPE_BITMASK_LTE; case NETWORK_TYPE_NR: return NETWORK_TYPE_BITMASK_NR; + case NETWORK_TYPE_NB_IOT_NTN: + return NETWORK_TYPE_BITMASK_NB_IOT_NTN; case NETWORK_TYPE_IWLAN: return NETWORK_TYPE_BITMASK_IWLAN; case NETWORK_TYPE_IDEN: @@ -6761,9 +6852,13 @@ public class TelephonyManager { } } - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"ERI_"}, value = { + -1, ERI_ON, ERI_OFF, ERI_FLASH @@ -6773,24 +6868,37 @@ public class TelephonyManager { /** * ERI (Enhanced Roaming Indicator) is ON i.e value 0 defined by * 3GPP2 C.R1001-H v1.0 Table 8.1-1. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int ERI_ON = 0; /** * ERI (Enhanced Roaming Indicator) is OFF i.e value 1 defined by * 3GPP2 C.R1001-H v1.0 Table 8.1-1. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int ERI_OFF = 1; /** * ERI (Enhanced Roaming Indicator) is FLASH i.e value 2 defined by * 3GPP2 C.R1001-H v1.0 Table 8.1-1. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int ERI_FLASH = 2; - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"ERI_ICON_MODE_"}, value = { + -1, ERI_ICON_MODE_NORMAL, ERI_ICON_MODE_FLASH }) @@ -6802,7 +6910,9 @@ public class TelephonyManager { * * Note: ERI is defined 3GPP2 C.R1001-H Table 8.1-1 * @hide + * @deprecated Legacy CDMA is unsupported. */ + @Deprecated public static final int ERI_ICON_MODE_NORMAL = 0; /** @@ -6811,7 +6921,9 @@ public class TelephonyManager { * * Note: ERI is defined 3GPP2 C.R1001-H Table 8.1-1 * @hide + * @deprecated Legacy CDMA is unsupported. */ + @Deprecated public static final int ERI_ICON_MODE_FLASH = 1; /** @@ -6819,10 +6931,13 @@ public class TelephonyManager { * 3GPP2 C.R1001-H v1.0 Table 8.1-1. Additionally carriers define their own ERI display numbers. * Defined values are {@link #ERI_ON}, {@link #ERI_OFF}, and {@link #ERI_FLASH}. * + * @deprecated Legacy CDMA is unsupported. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -6832,8 +6947,10 @@ public class TelephonyManager { /** * Returns the CDMA ERI icon index to display for a subscription. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @UnsupportedAppUsage public @EriIconIndex int getCdmaEriIconIndex(int subId) { @@ -6856,8 +6973,10 @@ public class TelephonyManager { * 0 - ON * 1 - FLASHING * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @UnsupportedAppUsage public @EriIconMode int getCdmaEriIconMode(int subId) { @@ -6878,8 +6997,10 @@ public class TelephonyManager { /** * Returns the CDMA ERI text, * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getCdmaEriText() { return getCdmaEriText(getSubId()); @@ -6888,8 +7009,10 @@ public class TelephonyManager { /** * Returns the CDMA ERI text, of a subscription * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @UnsupportedAppUsage public String getCdmaEriText(int subId) { @@ -8166,8 +8289,10 @@ public class TelephonyManager { * @param itemID the ID of the item to read. * @return the NV item as a String, or null on any failure. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated @UnsupportedAppUsage public String nvReadItem(int itemID) { try { @@ -8194,8 +8319,10 @@ public class TelephonyManager { * @param itemValue the value to write, as a String. * @return true on success; false on any failure. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public boolean nvWriteItem(int itemID, String itemValue) { try { ITelephony telephony = getITelephony(); @@ -8220,8 +8347,10 @@ public class TelephonyManager { * @param preferredRoamingList byte array containing the new PRL. * @return true on success; false on any failure. * + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public boolean nvWriteCdmaPrl(byte[] preferredRoamingList) { try { ITelephony telephony = getITelephony(); @@ -8248,12 +8377,19 @@ public class TelephonyManager { * {@link #resetRadioConfig()} for reset type 3 (b/116476729) * * @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset + * @deprecated NV APIs are deprecated starting from Android U. * @return true on success; false on any failure. * * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Deprecated public boolean nvResetConfig(int resetType) { + if (Flags.cleanupCdma()) { + if (resetType != 1) { // 1: reload NV reset (reboot modem) + return false; + } + } try { ITelephony telephony = getITelephony(); if (telephony != null) { @@ -8283,14 +8419,20 @@ public class TelephonyManager { * * @return {@code true} on success; {@code false} on any failure. * + * @deprecated NV APIs are deprecated starting from Android U. * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_RADIO_ACCESS}. * @hide */ + @Deprecated + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public boolean resetRadioConfig() { + if (Flags.cleanupCdma()) { + return false; + } try { ITelephony telephony = getITelephony(); if (telephony != null) { @@ -8319,6 +8461,7 @@ public class TelephonyManager { * {@link PackageManager#FEATURE_TELEPHONY_RADIO_ACCESS}. * @hide */ + @Deprecated @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @SystemApi @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) @@ -9272,20 +9415,26 @@ public class TelephonyManager { /** * Preferred network mode is CDMA and EvDo (auto mode, according to PRL). + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_CDMA_EVDO = RILConstants.NETWORK_MODE_CDMA; /** * Preferred network mode is CDMA only. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_CDMA_NO_EVDO = RILConstants.NETWORK_MODE_CDMA_NO_EVDO; /** * Preferred network mode is EvDo only. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_EVDO_NO_CDMA = RILConstants.NETWORK_MODE_EVDO_NO_CDMA; /** @@ -9296,8 +9445,10 @@ public class TelephonyManager { /** * Preferred network mode is LTE, CDMA and EvDo. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO; /** @@ -9308,8 +9459,10 @@ public class TelephonyManager { /** * Preferred network mode is LTE, CDMA, EvDo, GSM/WCDMA. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA; @@ -9379,14 +9532,18 @@ public class TelephonyManager { /** * Preferred network mode is TD-SCDMA,EvDo,CDMA,GSM/WCDMA. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; /** * Preferred network mode is TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; @@ -9404,8 +9561,10 @@ public class TelephonyManager { /** * Preferred network mode is NR 5G, LTE, CDMA and EvDo. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_NR_LTE_CDMA_EVDO = RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO; @@ -9418,8 +9577,10 @@ public class TelephonyManager { /** * Preferred network mode is NR 5G, LTE, CDMA, EvDo, GSM and WCDMA. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA = RILConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA; @@ -9458,8 +9619,10 @@ public class TelephonyManager { /** * Preferred network mode is NR 5G, LTE, TD-SCDMA, CDMA, EVDO, GSM and WCDMA. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public static final int NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = RILConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA; @@ -10160,6 +10323,9 @@ public class TelephonyManager { * This API will result in allowing an intersection of allowed network types for all reasons, * including the configuration done through other reasons. * + * If device supports satellite service, then + * {@link #NETWORK_TYPE_NB_IOT_NTN} is added to allowed network types for reason by default. + * * @param reason the reason the allowed network type change is taking place * @param allowedNetworkTypes The bitmask of allowed network type * @throws IllegalStateException if the Telephony process is not currently available. @@ -10209,6 +10375,10 @@ public class TelephonyManager { * <p>Requires permission: android.Manifest.READ_PRIVILEGED_PHONE_STATE or * that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). * + * If device supports satellite service, then + * {@link #NETWORK_TYPE_NB_IOT_NTN} is added to allowed network types for reason by + * default. + * * @param reason the reason the allowed network type change is taking place * @return the allowed network type bitmask * @throws IllegalStateException if the Telephony process is not currently available. @@ -10275,7 +10445,7 @@ public class TelephonyManager { */ public static String convertNetworkTypeBitmaskToString( @NetworkTypeBitMask long networkTypeBitmask) { - String networkTypeName = IntStream.rangeClosed(NETWORK_TYPE_GPRS, NETWORK_TYPE_NR) + String networkTypeName = IntStream.rangeClosed(NETWORK_TYPE_GPRS, NETWORK_TYPE_NB_IOT_NTN) .filter(x -> { return (networkTypeBitmask & getBitMaskForNetworkType(x)) == getBitMaskForNetworkType(x); @@ -10533,8 +10703,11 @@ public class TelephonyManager { /** * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -10545,8 +10718,11 @@ public class TelephonyManager { /** * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -10566,8 +10742,11 @@ public class TelephonyManager { /** * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -10578,8 +10757,11 @@ public class TelephonyManager { /** * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -11868,8 +12050,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -11912,8 +12097,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -11935,7 +12123,10 @@ public class TelephonyManager { } } - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated @IntDef(prefix = { "CDMA_SUBSCRIPTION_" }, value = { CDMA_SUBSCRIPTION_UNKNOWN, CDMA_SUBSCRIPTION_RUIM_SIM, @@ -11946,22 +12137,31 @@ public class TelephonyManager { /** * Used for CDMA subscription mode, it'll be UNKNOWN if there is no Subscription source. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi public static final int CDMA_SUBSCRIPTION_UNKNOWN = -1; /** * Used for CDMA subscription mode: RUIM/SIM (default) + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi public static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; /** * Used for CDMA subscription mode: NV -> non-volatile memory + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi public static final int CDMA_SUBSCRIPTION_NV = 1; @@ -11982,8 +12182,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -12022,8 +12225,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) @@ -13747,8 +13953,11 @@ public class TelephonyManager { * * @throws UnsupportedOperationException If the device does not have * {@link PackageManager#FEATURE_TELEPHONY_CDMA}. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA) public String getCdmaPrlVersion() { @@ -13762,8 +13971,10 @@ public class TelephonyManager { * * @param subId the subscription ID that this request applies to. * @return PRLVersion or null if error. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @Deprecated public String getCdmaPrlVersion(int subId) { try { ITelephony service = getITelephony(); @@ -14905,7 +15116,8 @@ public class TelephonyManager { NETWORK_TYPE_BITMASK_LTE_CA, NETWORK_TYPE_BITMASK_NR, NETWORK_TYPE_BITMASK_IWLAN, - NETWORK_TYPE_BITMASK_IDEN + NETWORK_TYPE_BITMASK_IDEN, + NETWORK_TYPE_BITMASK_NB_IOT_NTN }) public @interface NetworkTypeBitMask {} @@ -14928,7 +15140,10 @@ public class TelephonyManager { public static final long NETWORK_TYPE_BITMASK_EDGE = (1 << (NETWORK_TYPE_EDGE -1)); /** * network type bitmask indicating the support of radio tech CDMA(IS95A/IS95B). + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final long NETWORK_TYPE_BITMASK_CDMA = (1 << (NETWORK_TYPE_CDMA -1)); /** * network type bitmask indicating the support of radio tech 1xRTT. @@ -14950,7 +15165,10 @@ public class TelephonyManager { public static final long NETWORK_TYPE_BITMASK_EVDO_B = (1 << (NETWORK_TYPE_EVDO_B -1)); /** * network type bitmask indicating the support of radio tech EHRPD. + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final long NETWORK_TYPE_BITMASK_EHRPD = (1 << (NETWORK_TYPE_EHRPD -1)); /** * network type bitmask indicating the support of radio tech HSUPA. @@ -15006,6 +15224,12 @@ public class TelephonyManager { */ public static final long NETWORK_TYPE_BITMASK_IWLAN = (1 << (NETWORK_TYPE_IWLAN -1)); + /** + * network type bitmask indicating the support of readio tech NB IOT NTN. + */ + @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS) + public static final long NETWORK_TYPE_BITMASK_NB_IOT_NTN = (1 << (NETWORK_TYPE_NB_IOT_NTN - 1)); + /** @hide */ public static final long NETWORK_CLASS_BITMASK_2G = NETWORK_TYPE_BITMASK_GSM | NETWORK_TYPE_BITMASK_GPRS @@ -15034,6 +15258,9 @@ public class TelephonyManager { public static final long NETWORK_CLASS_BITMASK_5G = NETWORK_TYPE_BITMASK_NR; /** @hide */ + public static final long NETWORK_CLASS_BITMASK_NTN = NETWORK_TYPE_BITMASK_NB_IOT_NTN; + + /** @hide */ public static final long NETWORK_STANDARDS_FAMILY_BITMASK_3GPP = NETWORK_TYPE_BITMASK_GSM | NETWORK_TYPE_BITMASK_GPRS | NETWORK_TYPE_BITMASK_EDGE @@ -15045,9 +15272,13 @@ public class TelephonyManager { | NETWORK_TYPE_BITMASK_TD_SCDMA | NETWORK_TYPE_BITMASK_LTE | NETWORK_TYPE_BITMASK_LTE_CA - | NETWORK_TYPE_BITMASK_NR; + | NETWORK_TYPE_BITMASK_NR + | NETWORK_TYPE_BITMASK_NB_IOT_NTN; - /** @hide */ + /** @hide + * @deprecated Legacy CDMA is unsupported. + */ + @Deprecated public static final long NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2 = NETWORK_TYPE_BITMASK_CDMA | NETWORK_TYPE_BITMASK_1xRTT | NETWORK_TYPE_BITMASK_EVDO_0 @@ -18083,7 +18314,7 @@ public class TelephonyManager { */ public static boolean isNetworkTypeValid(@NetworkType int networkType) { return networkType >= TelephonyManager.NETWORK_TYPE_UNKNOWN && - networkType <= TelephonyManager.NETWORK_TYPE_NR; + networkType <= TelephonyManager.NETWORK_TYPE_NB_IOT_NTN; } /** diff --git a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java index 02429b5c2a2c..8fccf6505c0b 100644 --- a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java +++ b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java @@ -16,12 +16,15 @@ package android.telephony.cdma; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.telephony.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -34,18 +37,36 @@ import java.lang.annotation.RetentionPolicy; * containing an array of these objects to update its list of cell broadcast service categories * to display. * + * @deprecated Legacy CDMA is unsupported. * {@hide} */ +@FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) +@Deprecated @SystemApi public final class CdmaSmsCbProgramData implements Parcelable { - /** Delete the specified service category from the list of enabled categories. */ + /** + * Delete the specified service category from the list of enabled categories. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int OPERATION_DELETE_CATEGORY = 0; - /** Add the specified service category to the list of enabled categories. */ + /** + * Add the specified service category to the list of enabled categories. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int OPERATION_ADD_CATEGORY = 1; - /** Clear all service categories from the list of enabled categories. */ + /** + * Clear all service categories from the list of enabled categories. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int OPERATION_CLEAR_CATEGORIES = 2; /** @hide */ @@ -59,23 +80,53 @@ public final class CdmaSmsCbProgramData implements Parcelable { public @interface Operation {} // CMAS alert service category assignments, see 3GPP2 C.R1001 table 9.3.3-1 - /** Indicates a presidential-level alert */ + /** + * Indicates a presidential-level alert + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 0x1000; - /** Indicates an extreme threat to life and property */ + /** + * Indicates an extreme threat to life and property + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_EXTREME_THREAT = 0x1001; - /** Indicates an severe threat to life and property */ + /** + * Indicates an severe threat to life and property + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_SEVERE_THREAT = 0x1002; - /** Indicates an AMBER child abduction emergency */ + /** + * Indicates an AMBER child abduction emergency + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 0x1003; - /** Indicates a CMAS test message */ + /** + * Indicates a CMAS test message + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_TEST_MESSAGE = 0x1004; - /** The last reserved value of a CMAS service category according to 3GPP C.R1001 table - * 9.3.3-1. */ + /** + * The last reserved value of a CMAS service category according to 3GPP C.R1001 table + * 9.3.3-1. + * @deprecated Legacy CDMA is unsupported. + */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 0x10ff; /** @hide */ @@ -177,7 +228,10 @@ public final class CdmaSmsCbProgramData implements Parcelable { * * @param dest The Parcel in which the object should be written. * @param flags Additional flags about how the object should be written (ignored). + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mOperation); @@ -192,7 +246,10 @@ public final class CdmaSmsCbProgramData implements Parcelable { * Returns the service category operation, e.g. {@link #OPERATION_ADD_CATEGORY}. * * @return the service category operation + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public @Operation int getOperation() { return mOperation; } @@ -203,7 +260,10 @@ public final class CdmaSmsCbProgramData implements Parcelable { * 0x10FF are supported. * * @return a 16-bit CDMA service category value + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated public @Category int getCategory() { return mCategory; } @@ -255,7 +315,11 @@ public final class CdmaSmsCbProgramData implements Parcelable { /** * Describe the kinds of special objects contained in the marshalled representation. * @return a bitmask indicating this Parcelable contains no special objects + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @Override public int describeContents() { return 0; @@ -263,7 +327,11 @@ public final class CdmaSmsCbProgramData implements Parcelable { /** * Creator for unparcelling objects. + * + * @deprecated Legacy CDMA is unsupported. */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @NonNull public static final Parcelable.Creator<CdmaSmsCbProgramData> CREATOR = new Parcelable.Creator<CdmaSmsCbProgramData>() { diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index 8925a9e82942..76f83ee49dcd 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -18,6 +18,7 @@ package android.telephony.ims; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -37,6 +38,8 @@ import android.telephony.ims.aidl.IRcsUceControllerCallback; import android.telephony.ims.aidl.IRcsUcePublishStateCallback; import android.util.Log; +import com.android.internal.telephony.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -226,8 +229,11 @@ public class RcsUceAdapter { /** * A capability update has been requested due to moving to eHRPD. + * @deprecated Legacy CDMA is unsupported. * @hide */ + @FlaggedApi(Flags.FLAG_DEPRECATE_CDMA) + @Deprecated @SystemApi public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 4; diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index da7669fd81ad..74d9204e9c84 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -416,6 +416,8 @@ interface ITelephony { * Returns the CDMA ERI icon index to display * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaEriIconIndex(String callingPackage, String callingFeatureId); @@ -424,6 +426,8 @@ interface ITelephony { * @param subId user preferred subId. * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaEriIconIndexForSubscriber(int subId, String callingPackage, String callingFeatureId); @@ -434,6 +438,8 @@ interface ITelephony { * 1 - FLASHING * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaEriIconMode(String callingPackage, String callingFeatureId); @@ -444,6 +450,8 @@ interface ITelephony { * @param subId user preferred subId. * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaEriIconModeForSubscriber(int subId, String callingPackage, String callingFeatureId); @@ -452,6 +460,8 @@ interface ITelephony { * Returns the CDMA ERI text, * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ String getCdmaEriText(String callingPackage, String callingFeatureId); @@ -460,6 +470,8 @@ interface ITelephony { * @param subId user preferred subId. * @param callingPackage package making the call. * @param callingFeatureId The feature in the package. + * + * @deprecated Legacy CDMA is unsupported. */ String getCdmaEriTextForSubscriber(int subId, String callingPackage, String callingFeatureId); @@ -779,6 +791,8 @@ interface ITelephony { * * @param itemID the ID of the item to read. * @return the NV item as a String, or null on any failure. + * + * @deprecated Legacy CDMA is unsupported. */ String nvReadItem(int itemID); @@ -789,6 +803,8 @@ interface ITelephony { * @param itemID the ID of the item to read. * @param itemValue the value to write, as a String. * @return true on success; false on any failure. + * + * @deprecated Legacy CDMA is unsupported. */ boolean nvWriteItem(int itemID, String itemValue); @@ -798,6 +814,8 @@ interface ITelephony { * * @param preferredRoamingList byte array containing the new PRL. * @return true on success; false on any failure. + * + * @deprecated Legacy CDMA is unsupported. */ boolean nvWriteCdmaPrl(in byte[] preferredRoamingList); @@ -811,6 +829,8 @@ interface ITelephony { * * @param slotIndex - device slot. * @return {@code true} on success; {@code false} on any failure. + * + * @deprecated Legacy CDMA is unsupported. */ boolean resetModemConfig(int slotIndex); @@ -1041,12 +1061,16 @@ interface ITelephony { /** * Return MDN string for CDMA phone. * @param subId user preferred subId. + * + * @deprecated Legacy CDMA is unsupported. */ String getCdmaMdn(int subId); /** * Return MIN string for CDMA phone. * @param subId user preferred subId. + * + * @deprecated Legacy CDMA is unsupported. */ String getCdmaMin(int subId); @@ -1495,13 +1519,14 @@ interface ITelephony { String getEsn(int subId); /** - * Return the Preferred Roaming List Version - * - * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission - * @param subId the subscription ID that this request applies to. - * @return PRLVersion or null if error. - * @hide - */ + * Return the Preferred Roaming List Version + * + * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission + * @param subId the subscription ID that this request applies to. + * @return PRLVersion or null if error. + * @hide + * @deprecated Legacy CDMA is unsupported. + */ String getCdmaPrlVersion(int subId); /** @@ -1804,6 +1829,8 @@ interface ITelephony { * * @param the subscription id. * @return the roaming mode for CDMA phone. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaRoamingMode(int subId); @@ -1814,6 +1841,8 @@ interface ITelephony { * @param subId the subscription id. * @param mode the roaming mode should be set. * @return {@code true} if successed. + * + * @deprecated Legacy CDMA is unsupported. */ boolean setCdmaRoamingMode(int subId, int mode); @@ -1822,6 +1851,8 @@ interface ITelephony { * * @param the subscription id. * @return the subscription mode for CDMA phone. + * + * @deprecated Legacy CDMA is unsupported. */ int getCdmaSubscriptionMode(int subId); @@ -1832,6 +1863,8 @@ interface ITelephony { * @param subId the subscription id. * @param mode the subscription mode should be set. * @return {@code true} if successed. + * + * @deprecated Legacy CDMA is unsupported. */ boolean setCdmaSubscriptionMode(int subId, int mode); diff --git a/tests/Input/res/xml/bookmarks.xml b/tests/Input/res/xml/bookmarks.xml index a4c898d8159a..68ec1233cdd7 100644 --- a/tests/Input/res/xml/bookmarks.xml +++ b/tests/Input/res/xml/bookmarks.xml @@ -23,7 +23,7 @@ androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CONTACTS" - androidprv:keycode="KEYCODE_C" + androidprv:keycode="KEYCODE_P" androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_EMAIL" @@ -31,21 +31,13 @@ androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALENDAR" - androidprv:keycode="KEYCODE_K" + androidprv:keycode="KEYCODE_C" androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MAPS" androidprv:keycode="KEYCODE_M" androidprv:modifierState="META" /> <bookmark - category="android.intent.category.APP_MUSIC" - androidprv:keycode="KEYCODE_P" - androidprv:modifierState="META" /> - <bookmark - role="android.app.role.SMS" - androidprv:keycode="KEYCODE_S" - androidprv:modifierState="META" /> - <bookmark category="android.intent.category.APP_CALCULATOR" androidprv:keycode="KEYCODE_U" androidprv:modifierState="META" /> @@ -57,7 +49,7 @@ <bookmark category="android.intent.category.APP_CONTACTS" - androidprv:keycode="KEYCODE_C" + androidprv:keycode="KEYCODE_P" shift="true" /> <bookmark @@ -65,4 +57,4 @@ class="com.test.BookmarkTest" androidprv:keycode="KEYCODE_J" shift="true" /> -</bookmarks>
\ No newline at end of file +</bookmarks> diff --git a/tests/Input/res/xml/bookmarks_legacy.xml b/tests/Input/res/xml/bookmarks_legacy.xml index 8bacf490ad9e..78cc48b19416 100644 --- a/tests/Input/res/xml/bookmarks_legacy.xml +++ b/tests/Input/res/xml/bookmarks_legacy.xml @@ -22,23 +22,17 @@ shortcut="b" /> <bookmark category="android.intent.category.APP_CONTACTS" - shortcut="c" /> + shortcut="p" /> <bookmark category="android.intent.category.APP_EMAIL" shortcut="e" /> <bookmark category="android.intent.category.APP_CALENDAR" - shortcut="k" /> + shortcut="c" /> <bookmark category="android.intent.category.APP_MAPS" shortcut="m" /> <bookmark - category="android.intent.category.APP_MUSIC" - shortcut="p" /> - <bookmark - role="android.app.role.SMS" - shortcut="s" /> - <bookmark category="android.intent.category.APP_CALCULATOR" shortcut="u" /> @@ -49,7 +43,7 @@ <bookmark category="android.intent.category.APP_CONTACTS" - shortcut="c" + shortcut="p" shift="true" /> <bookmark @@ -57,4 +51,4 @@ class="com.test.BookmarkTest" shortcut="j" shift="true" /> -</bookmarks>
\ No newline at end of file +</bookmarks> diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt index 43844f6514e8..038c6d7754b5 100644 --- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt +++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt @@ -541,7 +541,8 @@ class InputManagerServiceTests { 0 }, "title", - /* uid = */0 + /* uid = */0, + /* inputFeatureFlags = */ 0 ) whenever(windowManagerInternal.getKeyInterceptionInfoFromToken(any())).thenReturn(info) } diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt index c6d281914f2c..fafb0e0f75c8 100644 --- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt @@ -575,9 +575,9 @@ class KeyGestureControllerTests { ), TestData( "META + C -> Launch Default Contacts", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_C), + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_P), KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_C), + intArrayOf(KeyEvent.KEYCODE_P), KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS) @@ -593,9 +593,9 @@ class KeyGestureControllerTests { ), TestData( "META + K -> Launch Default Calendar", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_K), + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_C), KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_K), + intArrayOf(KeyEvent.KEYCODE_C), KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALENDAR) @@ -610,24 +610,6 @@ class KeyGestureControllerTests { AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MAPS) ), TestData( - "META + P -> Launch Default Music", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_P), - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_P), - KeyEvent.META_META_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), - AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MUSIC) - ), - TestData( - "META + S -> Launch Default SMS", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_S), - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_S), - KeyEvent.META_META_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), - AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_SMS) - ), - TestData( "META + U -> Launch Default Calculator", intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_U), KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, @@ -872,10 +854,10 @@ class KeyGestureControllerTests { AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER) ), TestData( - "META + C -> Launch Default Contacts", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_C), + "META + P -> Launch Default Contacts", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_P), KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_C), + intArrayOf(KeyEvent.KEYCODE_P), KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS) @@ -890,10 +872,10 @@ class KeyGestureControllerTests { AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_EMAIL) ), TestData( - "META + K -> Launch Default Calendar", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_K), + "META + C -> Launch Default Calendar", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_C), KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_K), + intArrayOf(KeyEvent.KEYCODE_C), KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALENDAR) @@ -908,24 +890,6 @@ class KeyGestureControllerTests { AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MAPS) ), TestData( - "META + P -> Launch Default Music", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_P), - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_P), - KeyEvent.META_META_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), - AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MUSIC) - ), - TestData( - "META + S -> Launch Default SMS", - intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_S), - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_S), - KeyEvent.META_META_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), - AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_SMS) - ), - TestData( "META + U -> Launch Default Calculator", intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_U), KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, @@ -948,14 +912,14 @@ class KeyGestureControllerTests { AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER) ), TestData( - "META + SHIFT + C -> Launch Default Contacts", + "META + SHIFT + P -> Launch Default Contacts", intArrayOf( KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_SHIFT_LEFT, - KeyEvent.KEYCODE_C + KeyEvent.KEYCODE_P ), KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_C), + intArrayOf(KeyEvent.KEYCODE_P), KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS) @@ -1732,4 +1696,4 @@ class KeyGestureControllerTests { return true } } -}
\ No newline at end of file +} diff --git a/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java b/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java index cd2ab86d6444..055e159ff0b6 100644 --- a/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java +++ b/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.service.watchdog.ExplicitHealthCheckService.EXTRA_HEALTH_CHECK_PASSED_PACKAGE; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; @@ -35,8 +37,6 @@ public class ExplicitHealthCheckServiceTest { private ExplicitHealthCheckService mExplicitHealthCheckService; private static final String PACKAGE_NAME = "com.test.package"; - private static final String EXTRA_HEALTH_CHECK_PASSED_PACKAGE = - "android.service.watchdog.extra.health_check_passed_package"; @Before public void setup() throws Exception { @@ -52,7 +52,7 @@ public class ExplicitHealthCheckServiceTest { IBinder binder = mExplicitHealthCheckService.onBind(new Intent()); CountDownLatch countDownLatch = new CountDownLatch(1); RemoteCallback callback = new RemoteCallback(result -> { - assertThat(result.get(EXTRA_HEALTH_CHECK_PASSED_PACKAGE)) + assertThat(result.getString(EXTRA_HEALTH_CHECK_PASSED_PACKAGE)) .isEqualTo(PACKAGE_NAME); countDownLatch.countDown(); }); diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesMetadataProcessor.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesMetadataProcessor.kt index 100d869a663f..4a6d4b1f49ef 100644 --- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesMetadataProcessor.kt +++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesMetadataProcessor.kt @@ -17,8 +17,10 @@ package com.android.systemfeatures import android.annotation.SdkConstant +import com.squareup.javapoet.ClassName import com.squareup.javapoet.FieldSpec import com.squareup.javapoet.JavaFile +import com.squareup.javapoet.MethodSpec import com.squareup.javapoet.TypeSpec import java.io.IOException import javax.annotation.processing.AbstractProcessor @@ -27,6 +29,7 @@ import javax.annotation.processing.RoundEnvironment import javax.lang.model.SourceVersion import javax.lang.model.element.Modifier import javax.lang.model.element.TypeElement +import javax.lang.model.element.VariableElement import javax.tools.Diagnostic /* @@ -35,7 +38,16 @@ import javax.tools.Diagnostic * <p>The output is a single class file, `com.android.internal.pm.SystemFeaturesMetadata`, with * properties computed from feature constant definitions in the PackageManager class. This * class is only produced if the processed environment includes PackageManager; all other - * invocations are ignored. + * invocations are ignored. The generated API is as follows: + * + * <pre> + * package android.content.pm; + * public final class SystemFeaturesMetadata { + * public static final int SDK_FEATURE_COUNT; + * // @return [0, SDK_FEATURE_COUNT) if an SDK-defined system feature, -1 otherwise. + * public static int maybeGetSdkFeatureIndex(String featureName); + * } + * </pre> */ class SystemFeaturesMetadataProcessor : AbstractProcessor() { @@ -56,19 +68,31 @@ class SystemFeaturesMetadataProcessor : AbstractProcessor() { return false } - // We're only interested in feature constants defined in PackageManager. - var featureCount = 0 - roundEnv.getElementsAnnotatedWith(SdkConstant::class.java).forEach { - if ( - it.enclosingElement == packageManagerType && - it.getAnnotation(SdkConstant::class.java).value == - SdkConstant.SdkConstantType.FEATURE - ) { - featureCount++ - } - } + // Collect all FEATURE-annotated fields from PackageManager, and + // 1) Use the field values to de-duplicate, as there can be multiple FEATURE_* fields that + // map to the same feature string name value. + // 2) Ensure they're sorted to ensure consistency and determinism between builds. + val featureVarNames = + roundEnv + .getElementsAnnotatedWith(SdkConstant::class.java) + .asSequence() + .filter { + it.enclosingElement == packageManagerType && + it.getAnnotation(SdkConstant::class.java).value == + SdkConstant.SdkConstantType.FEATURE + } + .mapNotNull { element -> + (element as? VariableElement)?.let { varElement -> + varElement.getConstantValue()?.toString() to + varElement.simpleName.toString() + } + } + .toMap() + .values + .sorted() + .toList() - if (featureCount == 0) { + if (featureVarNames.isEmpty()) { // This is fine, and happens for any environment that doesn't include PackageManager. return false } @@ -77,16 +101,8 @@ class SystemFeaturesMetadataProcessor : AbstractProcessor() { TypeSpec.classBuilder("SystemFeaturesMetadata") .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addJavadoc("@hide") - .addField( - FieldSpec.builder(Int::class.java, "SDK_FEATURE_COUNT") - .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) - .addJavadoc( - "The number of `@SdkConstant` features defined in PackageManager." - ) - .addJavadoc("@hide") - .initializer("\$L", featureCount) - .build() - ) + .addField(buildFeatureCount(featureVarNames)) + .addMethod(buildFeatureIndexLookup(featureVarNames)) .build() try { @@ -104,7 +120,41 @@ class SystemFeaturesMetadataProcessor : AbstractProcessor() { return true } + private fun buildFeatureCount(featureVarNames: Collection<String>): FieldSpec { + return FieldSpec.builder(Int::class.java, "SDK_FEATURE_COUNT") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) + .addJavadoc( + "# of {@link android.annotation.SdkConstant}` features defined in PackageManager." + ) + .addJavadoc("\n\n@hide") + .initializer("\$L", featureVarNames.size) + .build() + } + + private fun buildFeatureIndexLookup(featureVarNames: Collection<String>): MethodSpec { + val methodBuilder = + MethodSpec.methodBuilder("maybeGetSdkFeatureIndex") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .addJavadoc("@return an index in [0, SDK_FEATURE_COUNT) for features defined ") + .addJavadoc("in PackageManager, else -1.") + .addJavadoc("\n\n@hide") + .returns(Int::class.java) + .addParameter(String::class.java, "featureName") + methodBuilder.beginControlFlow("switch (featureName)") + featureVarNames.forEachIndexed { index, featureVarName -> + methodBuilder + .addCode("case \$T.\$N: ", PACKAGEMANAGER_CLASS, featureVarName) + .addStatement("return \$L", index) + } + methodBuilder + .addCode("default: ") + .addStatement("return -1") + .endControlFlow() + return methodBuilder.build() + } + companion object { private val SDK_CONSTANT_ANNOTATION_NAME = SdkConstant::class.qualifiedName + private val PACKAGEMANAGER_CLASS = ClassName.get("android.content.pm", "PackageManager") } } diff --git a/tools/systemfeatures/tests/src/SystemFeaturesMetadataProcessorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesMetadataProcessorTest.java index 4ffb5b979d75..74ce6daaffc4 100644 --- a/tools/systemfeatures/tests/src/SystemFeaturesMetadataProcessorTest.java +++ b/tools/systemfeatures/tests/src/SystemFeaturesMetadataProcessorTest.java @@ -16,10 +16,16 @@ package com.android.systemfeatures; +import static com.android.internal.pm.SystemFeaturesMetadata.maybeGetSdkFeatureIndex; + import static com.google.common.truth.Truth.assertThat; +import android.content.pm.PackageManager; + import com.android.internal.pm.SystemFeaturesMetadata; +import com.google.common.collect.Range; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -33,4 +39,17 @@ public class SystemFeaturesMetadataProcessorTest { // It defines 5 annotated features, and any/all other constants should be ignored. assertThat(SystemFeaturesMetadata.SDK_FEATURE_COUNT).isEqualTo(5); } + + @Test + public void testSdkFeatureIndex() { + // Only SDK-defined features return valid indices. + final Range validIndexRange = Range.closedOpen(0, SystemFeaturesMetadata.SDK_FEATURE_COUNT); + assertThat(maybeGetSdkFeatureIndex(PackageManager.FEATURE_PC)).isIn(validIndexRange); + assertThat(maybeGetSdkFeatureIndex(PackageManager.FEATURE_VULKAN)).isIn(validIndexRange); + assertThat(maybeGetSdkFeatureIndex(PackageManager.FEATURE_NOT_ANNOTATED)).isEqualTo(-1); + assertThat(maybeGetSdkFeatureIndex(PackageManager.NOT_FEATURE)).isEqualTo(-1); + assertThat(maybeGetSdkFeatureIndex("foo")).isEqualTo(-1); + assertThat(maybeGetSdkFeatureIndex("0")).isEqualTo(-1); + assertThat(maybeGetSdkFeatureIndex("")).isEqualTo(-1); + } } |